958c79167bb036099ee2391c986f886ec05c766b
[blender.git] / source / blender / editors / space_action / action_edit.c
1 /**
2  * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <float.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
43
44 #include "DNA_listBase.h"
45 #include "DNA_action_types.h"
46 #include "DNA_armature_types.h"
47 #include "DNA_camera_types.h"
48 #include "DNA_curve_types.h"
49 #include "DNA_ipo_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_space_types.h"
54 #include "DNA_constraint_types.h"
55 #include "DNA_key_types.h"
56 #include "DNA_lamp_types.h"
57 #include "DNA_material_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_gpencil_types.h"
60 #include "DNA_windowmanager_types.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64
65 #include "BKE_action.h"
66 #include "BKE_depsgraph.h"
67 #include "BKE_ipo.h"
68 #include "BKE_key.h"
69 #include "BKE_material.h"
70 #include "BKE_object.h"
71 #include "BKE_context.h"
72 #include "BKE_utildefines.h"
73
74 #include "UI_view2d.h"
75
76 #include "ED_anim_api.h"
77 #include "ED_keyframing.h"
78 #include "ED_keyframes_draw.h"
79 #include "ED_keyframes_edit.h"
80 #include "ED_screen.h"
81 #include "ED_space_api.h"
82
83 #include "WM_api.h"
84 #include "WM_types.h"
85
86 #include "action_intern.h"
87
88 /* ************************************************************************** */
89 /* GENERAL STUFF */
90
91 // TODO:
92 //      - insert key
93
94 /* ******************** Copy/Paste Keyframes Operator ************************* */
95 /* - The copy/paste buffer currently stores a set of Action Channels, with temporary
96  *      IPO-blocks, and also temporary IpoCurves which only contain the selected keyframes.
97  * - Only pastes between compatable data is possible (i.e. same achan->name, ipo-curve type, etc.)
98  *      Unless there is only one element in the buffer, names are also tested to check for compatability.
99  * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
100  *      the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
101  * - The earliest frame is calculated per copy operation.
102  */
103
104 /* globals for copy/paste data (like for other copy/paste buffers) */
105 ListBase actcopybuf = {NULL, NULL};
106 static float actcopy_firstframe= 999999999.0f;
107
108 /* This function frees any MEM_calloc'ed copy/paste buffer data */
109 // XXX find some header to put this in!
110 void free_actcopybuf ()
111 {
112         bActionChannel *achan, *anext;
113         bConstraintChannel *conchan, *cnext;
114         
115         for (achan= actcopybuf.first; achan; achan= anext) {
116                 anext= achan->next;
117                 
118                 if (achan->ipo) {
119                         free_ipo(achan->ipo);
120                         MEM_freeN(achan->ipo);
121                 }
122                 
123                 for (conchan=achan->constraintChannels.first; conchan; conchan=cnext) {
124                         cnext= conchan->next;
125                         
126                         if (conchan->ipo) {
127                                 free_ipo(conchan->ipo);
128                                 MEM_freeN(conchan->ipo);
129                         }
130                         
131                         BLI_freelinkN(&achan->constraintChannels, conchan);
132                 }
133                 
134                 BLI_freelinkN(&actcopybuf, achan);
135         }
136         
137         actcopybuf.first= actcopybuf.last= NULL;
138         actcopy_firstframe= 999999999.0f;
139 }
140
141 /* ------------------- */
142
143 /* This function adds data to the copy/paste buffer, freeing existing data first
144  * Only the selected action channels gets their selected keyframes copied.
145  */
146 static short copy_action_keys (bAnimContext *ac)
147 {
148         ListBase anim_data = {NULL, NULL};
149         bAnimListElem *ale;
150         int filter;
151         
152         /* clear buffer first */
153         free_actcopybuf();
154         
155         /* filter data */
156         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_IPOKEYS);
157         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
158         
159         /* assume that each of these is an ipo-block */
160         for (ale= anim_data.first; ale; ale= ale->next) {
161                 bActionChannel *achan;
162                 Ipo *ipo= ale->key_data;
163                 Ipo *ipn;
164                 IpoCurve *icu, *icn;
165                 BezTriple *bezt;
166                 int i;
167                 
168                 /* coerce an action-channel out of owner */
169                 if (ale->ownertype == ANIMTYPE_ACHAN) {
170                         bActionChannel *achanO= ale->owner;
171                         achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
172                         strcpy(achan->name, achanO->name);
173                 }
174                 else if (ale->ownertype == ANIMTYPE_SHAPEKEY) {
175                         achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
176                         strcpy(achan->name, "#ACP_ShapeKey");
177                 }
178                 else
179                         continue;
180                 BLI_addtail(&actcopybuf, achan);
181                 
182                 /* add constraint channel if needed, then add new ipo-block */
183                 if (ale->type == ANIMTYPE_CONCHAN) {
184                         bConstraintChannel *conchanO= ale->data;
185                         bConstraintChannel *conchan;
186                         
187                         conchan= MEM_callocN(sizeof(bConstraintChannel), "ActCopyPasteConchan");
188                         strcpy(conchan->name, conchanO->name);
189                         BLI_addtail(&achan->constraintChannels, conchan);
190                         
191                         conchan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
192                 }
193                 else {
194                         achan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
195                 }
196                 ipn->blocktype = ipo->blocktype;
197                 
198                 /* now loop through curves, and only copy selected keyframes */
199                 for (icu= ipo->curve.first; icu; icu= icu->next) {
200                         /* allocate a new curve */
201                         icn= MEM_callocN(sizeof(IpoCurve), "ActCopyPasteIcu");
202                         icn->blocktype = icu->blocktype;
203                         icn->adrcode = icu->adrcode;
204                         BLI_addtail(&ipn->curve, icn);
205                         
206                         /* find selected BezTriples to add to the buffer (and set first frame) */
207                         for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
208                                 if (BEZSELECTED(bezt)) {
209                                         /* add to buffer ipo-curve */
210                                         insert_bezt_icu(icn, bezt);
211                                         
212                                         /* check if this is the earliest frame encountered so far */
213                                         if (bezt->vec[1][0] < actcopy_firstframe)
214                                                 actcopy_firstframe= bezt->vec[1][0];
215                                 }
216                         }
217                 }
218         }
219         
220         /* check if anything ended up in the buffer */
221         if (ELEM(NULL, actcopybuf.first, actcopybuf.last))
222         //      error("Nothing copied to buffer");
223                 return -1;
224         
225         /* free temp memory */
226         BLI_freelistN(&anim_data);
227         
228         /* everything went fine */
229         return 0;
230 }
231
232 static short paste_action_keys (bAnimContext *ac)
233 {
234         ListBase anim_data = {NULL, NULL};
235         bAnimListElem *ale;
236         int filter;
237         
238         const Scene *scene= (ac->scene);
239         const float offset = (float)(CFRA - actcopy_firstframe);
240         char *actname = NULL, *conname = NULL;
241         short no_name= 0;
242         
243         /* check if buffer is empty */
244         if (ELEM(NULL, actcopybuf.first, actcopybuf.last)) {
245                 //error("No data in buffer to paste");
246                 return -1;
247         }
248         /* check if single channel in buffer (disregard names if so)  */
249         if (actcopybuf.first == actcopybuf.last)
250                 no_name= 1;
251         
252         /* filter data */
253         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
254         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
255         
256         /* from selected channels */
257         for (ale= anim_data.first; ale; ale= ale->next) {
258                 Ipo *ipo_src = NULL;
259                 bActionChannel *achan;
260                 IpoCurve *ico, *icu;
261                 BezTriple *bezt;
262                 int i;
263                 
264                 /* find suitable IPO-block from buffer to paste from */
265                 for (achan= actcopybuf.first; achan; achan= achan->next) {
266                         /* try to match data */
267                         if (ale->ownertype == ANIMTYPE_ACHAN) {
268                                 bActionChannel *achant= ale->owner;
269                                 
270                                 /* check if we have a corresponding action channel */
271                                 if ((no_name) || (strcmp(achan->name, achant->name)==0)) {
272                                         actname= achant->name;
273                                         
274                                         /* check if this is a constraint channel */
275                                         if (ale->type == ANIMTYPE_CONCHAN) {
276                                                 bConstraintChannel *conchant= ale->data;
277                                                 bConstraintChannel *conchan;
278                                                 
279                                                 for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
280                                                         if (strcmp(conchan->name, conchant->name)==0) {
281                                                                 conname= conchant->name;
282                                                                 ipo_src= conchan->ipo;
283                                                                 break;
284                                                         }
285                                                 }
286                                                 if (ipo_src) break;
287                                         }
288                                         else {
289                                                 ipo_src= achan->ipo;
290                                                 break;
291                                         }
292                                 }
293                         }
294                         else if (ale->ownertype == ANIMTYPE_SHAPEKEY) {
295                                 /* check if this action channel is "#ACP_ShapeKey" */
296                                 if ((no_name) || (strcmp(achan->name, "#ACP_ShapeKey")==0)) {
297                                         actname= NULL;
298                                         ipo_src= achan->ipo;
299                                         break;
300                                 }
301                         }       
302                 }
303                 
304                 /* this shouldn't happen, but it might */
305                 if (ipo_src == NULL)
306                         continue;
307                 
308                 /* loop over curves, pasting keyframes */
309                 for (ico= ipo_src->curve.first; ico; ico= ico->next) {
310                         /* get IPO-curve to paste to (IPO-curve might not exist for destination, so gets created) */
311                         icu= verify_ipocurve(ale->id, ico->blocktype, actname, conname, NULL, ico->adrcode, 1);
312                         
313                         if (icu) {
314                                 /* just start pasting, with the the first keyframe on the current frame, and so on */
315                                 for (i=0, bezt=ico->bezt; i < ico->totvert; i++, bezt++) {                                              
316                                         /* temporarily apply offset to src beztriple while copying */
317                                         bezt->vec[0][0] += offset;
318                                         bezt->vec[1][0] += offset;
319                                         bezt->vec[2][0] += offset;
320                                         
321                                         /* insert the keyframe */
322                                         insert_bezt_icu(icu, bezt);
323                                         
324                                         /* un-apply offset from src beztriple after copying */
325                                         bezt->vec[0][0] -= offset;
326                                         bezt->vec[1][0] -= offset;
327                                         bezt->vec[2][0] -= offset;
328                                 }
329                                 
330                                 /* recalculate channel's handles? */
331                                 calchandles_ipocurve(icu);
332                         }
333                 }
334         }
335         
336         /* free temp memory */
337         BLI_freelistN(&anim_data);
338         
339         /* do depsgraph updates (for 3d-view)? */
340 #if 0
341         if ((ob) && (G.saction->pin==0)) {
342                 if (ob->type == OB_ARMATURE)
343                         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
344                 else
345                         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
346         }
347 #endif
348
349         return 0;
350 }
351
352 /* ------------------- */
353
354 static int actkeys_copy_exec(bContext *C, wmOperator *op)
355 {
356         bAnimContext ac;
357         
358         /* get editor data */
359         if (ANIM_animdata_get_context(C, &ac) == 0)
360                 return OPERATOR_CANCELLED;
361         
362         /* copy keyframes */
363         if (ac.datatype == ANIMCONT_GPENCIL) {
364                 // FIXME...
365         }
366         else {
367                 if (copy_action_keys(&ac)) {    
368                         // XXX errors - need a way to inform the user 
369                         printf("Action Copy: No keyframes copied to copy-paste buffer\n");
370                 }
371         }
372         
373         /* set notifier tha things have changed */
374         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
375         
376         return OPERATOR_FINISHED;
377 }
378  
379 void ACT_OT_keyframes_copy (wmOperatorType *ot)
380 {
381         /* identifiers */
382         ot->name= "Copy Keyframes";
383         ot->idname= "ACT_OT_keyframes_copy";
384         
385         /* api callbacks */
386         ot->exec= actkeys_copy_exec;
387         ot->poll= ED_operator_areaactive;
388         
389         /* flags */
390         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
391 }
392
393
394
395 static int actkeys_paste_exec(bContext *C, wmOperator *op)
396 {
397         bAnimContext ac;
398         
399         /* get editor data */
400         if (ANIM_animdata_get_context(C, &ac) == 0)
401                 return OPERATOR_CANCELLED;
402         
403         /* paste keyframes */
404         if (ac.datatype == ANIMCONT_GPENCIL) {
405                 // FIXME...
406         }
407         else {
408                 if (paste_action_keys(&ac)) {
409                         // XXX errors - need a way to inform the user 
410                         printf("Action Paste: Nothing to paste, as Copy-Paste buffer was empty.\n");
411                 }
412         }
413         
414         /* validate keyframes after editing */
415         ANIM_editkeyframes_refresh(&ac);
416         
417         /* set notifier tha things have changed */
418         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
419         
420         return OPERATOR_FINISHED;
421 }
422  
423 void ACT_OT_keyframes_paste (wmOperatorType *ot)
424 {
425         /* identifiers */
426         ot->name= "Paste Keyframes";
427         ot->idname= "ACT_OT_keyframes_paste";
428         
429         /* api callbacks */
430         ot->exec= actkeys_paste_exec;
431         ot->poll= ED_operator_areaactive;
432         
433         /* flags */
434         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
435 }
436
437 /* ******************** Delete Keyframes Operator ************************* */
438
439 static void delete_action_keys (bAnimContext *ac)
440 {
441         ListBase anim_data = {NULL, NULL};
442         bAnimListElem *ale;
443         int filter;
444         
445         /* filter data */
446         if (ac->datatype == ANIMCONT_GPENCIL)
447                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
448         else
449                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
450         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
451         
452         /* loop through filtered data and delete selected keys */
453         for (ale= anim_data.first; ale; ale= ale->next) {
454                 //if (ale->type == ANIMTYPE_GPLAYER)
455                 //      delete_gplayer_frames((bGPDlayer *)ale->data);
456                 //else
457                         delete_ipo_keys((Ipo *)ale->key_data);
458         }
459         
460         /* free filtered list */
461         BLI_freelistN(&anim_data);
462 }
463
464 /* ------------------- */
465
466 static int actkeys_delete_exec(bContext *C, wmOperator *op)
467 {
468         bAnimContext ac;
469         
470         /* get editor data */
471         if (ANIM_animdata_get_context(C, &ac) == 0)
472                 return OPERATOR_CANCELLED;
473                 
474         /* delete keyframes */
475         delete_action_keys(&ac);
476         
477         /* validate keyframes after editing */
478         ANIM_editkeyframes_refresh(&ac);
479         
480         /* set notifier tha things have changed */
481         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
482         
483         return OPERATOR_FINISHED;
484 }
485  
486 void ACT_OT_keyframes_delete (wmOperatorType *ot)
487 {
488         /* identifiers */
489         ot->name= "Delete Keyframes";
490         ot->idname= "ACT_OT_keyframes_delete";
491         
492         /* api callbacks */
493         ot->exec= actkeys_delete_exec;
494         ot->poll= ED_operator_areaactive;
495         
496         /* flags */
497         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
498 }
499
500 /* ******************** Clean Keyframes Operator ************************* */
501
502 static void clean_action_keys (bAnimContext *ac, float thresh)
503 {       
504         ListBase anim_data = {NULL, NULL};
505         bAnimListElem *ale;
506         int filter;
507         
508         /* filter data */
509         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_ONLYICU);
510         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
511         
512         /* loop through filtered data and clean curves */
513         for (ale= anim_data.first; ale; ale= ale->next)
514                 clean_ipo_curve((IpoCurve *)ale->key_data, thresh);
515         
516         /* free temp data */
517         BLI_freelistN(&anim_data);
518 }
519
520 /* ------------------- */
521
522 static int actkeys_clean_exec(bContext *C, wmOperator *op)
523 {
524         bAnimContext ac;
525         float thresh;
526         
527         /* get editor data */
528         if (ANIM_animdata_get_context(C, &ac) == 0)
529                 return OPERATOR_CANCELLED;
530         if (ac.datatype == ANIMCONT_GPENCIL)
531                 return OPERATOR_PASS_THROUGH;
532                 
533         /* get cleaning threshold */
534         thresh= RNA_float_get(op->ptr, "threshold");
535         
536         /* clean keyframes */
537         clean_action_keys(&ac, thresh);
538         
539         /* validate keyframes after editing */
540         ANIM_editkeyframes_refresh(&ac);
541         
542         /* set notifier tha things have changed */
543         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
544         
545         return OPERATOR_FINISHED;
546 }
547  
548 void ACT_OT_keyframes_clean (wmOperatorType *ot)
549 {
550         PropertyRNA *prop;
551         
552         /* identifiers */
553         ot->name= "Clean Keyframes";
554         ot->idname= "ACT_OT_keyframes_clean";
555         
556         /* api callbacks */
557         //ot->invoke=  // XXX we need that number popup for this! 
558         ot->exec= actkeys_clean_exec;
559         ot->poll= ED_operator_areaactive;
560         
561         /* flags */
562         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
563         
564         /* properties */
565         prop= RNA_def_property(ot->srna, "threshold", PROP_FLOAT, PROP_NONE);
566         RNA_def_property_float_default(prop, 0.001f);
567 }
568
569 /* ******************** Sample Keyframes Operator *********************** */
570
571 /* little cache for values... */
572 typedef struct tempFrameValCache {
573         float frame, val;
574 } tempFrameValCache;
575
576 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
577 static void sample_action_keys (bAnimContext *ac)
578 {       
579         ListBase anim_data = {NULL, NULL};
580         bAnimListElem *ale;
581         int filter;
582         
583         /* filter data */
584         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ONLYICU);
585         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
586         
587         /* loop through filtered data and add keys between selected keyframes on every frame  */
588         for (ale= anim_data.first; ale; ale= ale->next) {
589                 IpoCurve *icu= (IpoCurve *)ale->key_data;
590                 BezTriple *bezt, *start=NULL, *end=NULL;
591                 tempFrameValCache *value_cache, *fp;
592                 int sfra, range;
593                 int i, n;
594                 
595                 /* find selected keyframes... once pair has been found, add keyframes  */
596                 for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
597                         /* check if selected, and which end this is */
598                         if (BEZSELECTED(bezt)) {
599                                 if (start) {
600                                         /* set end */
601                                         end= bezt;
602                                         
603                                         /* cache values then add keyframes using these values, as adding
604                                          * keyframes while sampling will affect the outcome...
605                                          */
606                                         range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
607                                         sfra= (int)( floor(start->vec[1][0]) );
608                                         
609                                         if (range) {
610                                                 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
611                                                 
612                                                 /*      sample values   */
613                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
614                                                         fp->frame= (float)(sfra + n);
615                                                         fp->val= eval_icu(icu, fp->frame);
616                                                 }
617                                                 
618                                                 /*      add keyframes with these        */
619                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
620                                                         insert_vert_icu(icu, fp->frame, fp->val, 1);
621                                                 }
622                                                 
623                                                 /* free temp cache */
624                                                 MEM_freeN(value_cache);
625                                                 
626                                                 /* as we added keyframes, we need to compensate so that bezt is at the right place */
627                                                 bezt = icu->bezt + i + range - 1;
628                                                 i += (range - 1);
629                                         }
630                                         
631                                         /* bezt was selected, so it now marks the start of a whole new chain to search */
632                                         start= bezt;
633                                         end= NULL;
634                                 }
635                                 else {
636                                         /* just set start keyframe */
637                                         start= bezt;
638                                         end= NULL;
639                                 }
640                         }
641                 }
642                 
643                 /* recalculate channel's handles? */
644                 calchandles_ipocurve(icu);
645         }
646         
647         /* admin and redraws */
648         BLI_freelistN(&anim_data);
649 }
650
651 /* ------------------- */
652
653 static int actkeys_sample_exec(bContext *C, wmOperator *op)
654 {
655         bAnimContext ac;
656         
657         /* get editor data */
658         if (ANIM_animdata_get_context(C, &ac) == 0)
659                 return OPERATOR_CANCELLED;
660         if (ac.datatype == ANIMCONT_GPENCIL)
661                 return OPERATOR_PASS_THROUGH;
662         
663         /* sample keyframes */
664         sample_action_keys(&ac);
665         
666         /* validate keyframes after editing */
667         ANIM_editkeyframes_refresh(&ac);
668         
669         /* set notifier tha things have changed */
670         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
671         
672         return OPERATOR_FINISHED;
673 }
674  
675 void ACT_OT_keyframes_sample (wmOperatorType *ot)
676 {
677         /* identifiers */
678         ot->name= "Sample Keyframes";
679         ot->idname= "ACT_OT_keyframes_sample";
680         
681         /* api callbacks */
682         ot->exec= actkeys_sample_exec;
683         ot->poll= ED_operator_areaactive;
684         
685         /* flags */
686         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
687 }
688
689 /* ************************************************************************** */
690 /* SETTINGS STUFF */
691
692 /* ******************** Set Extrapolation-Type Operator *********************** */
693
694 /* defines for set ipo-type for selected keyframes tool */
695 EnumPropertyItem prop_actkeys_expo_types[] = {
696         {IPO_HORIZ, "CONSTANT", "Constant", ""},
697         {IPO_DIR, "DIRECTIONAL", "Extrapolation", ""},
698         {IPO_CYCL, "CYCLIC", "Cyclic", ""},
699         {IPO_CYCLX, "CYCLIC_EXTRAPOLATION", "Cyclic Extrapolation", ""},
700         {0, NULL, NULL, NULL}
701 };
702
703 /* this function is responsible for setting extrapolation mode for keyframes */
704 static void setexpo_action_keys(bAnimContext *ac, short mode) 
705 {
706         ListBase anim_data = {NULL, NULL};
707         bAnimListElem *ale;
708         int filter;
709         
710         /* filter data */
711         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
712         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
713         
714         /* loop through setting mode per ipo-curve */
715         for (ale= anim_data.first; ale; ale= ale->next)
716                 setexprap_ipoloop(ale->key_data, mode);
717         
718         /* cleanup */
719         BLI_freelistN(&anim_data);
720 }
721
722 /* ------------------- */
723
724 static int actkeys_expo_exec(bContext *C, wmOperator *op)
725 {
726         bAnimContext ac;
727         short mode;
728         
729         /* get editor data */
730         if (ANIM_animdata_get_context(C, &ac) == 0)
731                 return OPERATOR_CANCELLED;
732         if (ac.datatype == ANIMCONT_GPENCIL) 
733                 return OPERATOR_PASS_THROUGH;
734                 
735         /* get handle setting mode */
736         mode= RNA_enum_get(op->ptr, "type");
737         
738         /* set handle type */
739         setexpo_action_keys(&ac, mode);
740         
741         /* validate keyframes after editing */
742         ANIM_editkeyframes_refresh(&ac);
743         
744         /* set notifier tha things have changed */
745         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
746         
747         return OPERATOR_FINISHED;
748 }
749  
750 void ACT_OT_keyframes_expotype (wmOperatorType *ot)
751 {
752         PropertyRNA *prop;
753         
754         /* identifiers */
755         ot->name= "Set Keyframe Extrapolation";
756         ot->idname= "ACT_OT_keyframes_expotype";
757         
758         /* api callbacks */
759         ot->invoke= WM_menu_invoke;
760         ot->exec= actkeys_expo_exec;
761         ot->poll= ED_operator_areaactive;
762         
763         /* flags */
764         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
765         
766         /* id-props */
767         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
768         RNA_def_property_enum_items(prop, prop_actkeys_expo_types);
769 }
770
771 /* ******************** Set Interpolation-Type Operator *********************** */
772
773 /* defines for set ipo-type for selected keyframes tool */
774 EnumPropertyItem prop_actkeys_ipo_types[] = {
775         {IPO_CONST, "CONSTANT", "Constant Interpolation", ""},
776         {IPO_LIN, "LINEAR", "Linear Interpolation", ""},
777         {IPO_BEZ, "BEZIER", "Bezier Interpolation", ""},
778         {0, NULL, NULL, NULL}
779 };
780
781 /* this function is responsible for setting interpolation mode for keyframes */
782 static void setipo_action_keys(bAnimContext *ac, short mode) 
783 {
784         ListBase anim_data = {NULL, NULL};
785         bAnimListElem *ale;
786         int filter;
787         BeztEditFunc set_cb= ANIM_editkeyframes_ipo(mode);
788         
789         /* filter data */
790         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
791         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
792         
793         /* loop through setting BezTriple interpolation
794          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
795          */
796         for (ale= anim_data.first; ale; ale= ale->next)
797                 ipo_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, ANIM_editkeyframes_ipocurve_ipotype);
798         
799         /* cleanup */
800         BLI_freelistN(&anim_data);
801 }
802
803 /* ------------------- */
804
805 static int actkeys_ipo_exec(bContext *C, wmOperator *op)
806 {
807         bAnimContext ac;
808         short mode;
809         
810         /* get editor data */
811         if (ANIM_animdata_get_context(C, &ac) == 0)
812                 return OPERATOR_CANCELLED;
813         if (ac.datatype == ANIMCONT_GPENCIL) 
814                 return OPERATOR_PASS_THROUGH;
815                 
816         /* get handle setting mode */
817         mode= RNA_enum_get(op->ptr, "type");
818         
819         /* set handle type */
820         setipo_action_keys(&ac, mode);
821         
822         /* validate keyframes after editing */
823         ANIM_editkeyframes_refresh(&ac);
824         
825         /* set notifier tha things have changed */
826         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
827         
828         return OPERATOR_FINISHED;
829 }
830  
831 void ACT_OT_keyframes_ipotype (wmOperatorType *ot)
832 {
833         PropertyRNA *prop;
834         
835         /* identifiers */
836         ot->name= "Set Keyframe Interpolation";
837         ot->idname= "ACT_OT_keyframes_ipotype";
838         
839         /* api callbacks */
840         ot->invoke= WM_menu_invoke;
841         ot->exec= actkeys_ipo_exec;
842         ot->poll= ED_operator_areaactive;
843         
844         /* flags */
845         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
846         
847         /* id-props */
848         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
849         RNA_def_property_enum_items(prop, prop_actkeys_ipo_types);
850 }
851
852 /* ******************** Set Handle-Type Operator *********************** */
853
854 /* defines for set handle-type for selected keyframes tool */
855 EnumPropertyItem prop_actkeys_handletype_types[] = {
856         {HD_AUTO, "AUTO", "Auto Handles", ""},
857         {HD_VECT, "VECTOR", "Vector Handles", ""},
858         {HD_FREE, "FREE", "Free Handles", ""},
859         {HD_ALIGN, "ALIGN", "Aligned Handles", ""},
860 //      {-1, "TOGGLE", "Toggle between Free and Aligned Handles", ""},
861         {0, NULL, NULL, NULL}
862 };
863
864 /* this function is responsible for setting handle-type of selected keyframes */
865 static void sethandles_action_keys(bAnimContext *ac, short mode) 
866 {
867         ListBase anim_data = {NULL, NULL};
868         bAnimListElem *ale;
869         int filter;
870         BeztEditFunc set_cb= ANIM_editkeyframes_handles(mode);
871         
872         /* filter data */
873         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
874         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
875         
876         /* loop through setting flags for handles 
877          * Note: we do not supply BeztEditData to the looper yet. Currently that's not necessary here...
878          */
879         for (ale= anim_data.first; ale; ale= ale->next) {
880                 if (mode == -1) {       
881                         BeztEditFunc toggle_cb;
882                         
883                         /* check which type of handle to set (free or aligned) 
884                          *      - check here checks for handles with free alignment already
885                          */
886                         if (ipo_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, NULL))
887                                 toggle_cb= ANIM_editkeyframes_handles(HD_FREE);
888                         else
889                                 toggle_cb= ANIM_editkeyframes_handles(HD_ALIGN);
890                                 
891                         /* set handle-type */
892                         ipo_keys_bezier_loop(NULL, ale->key_data, NULL, toggle_cb, calchandles_ipocurve);
893                 }
894                 else {
895                         /* directly set handle-type */
896                         ipo_keys_bezier_loop(NULL, ale->key_data, NULL, set_cb, calchandles_ipocurve);
897                 }
898         }
899         
900         /* cleanup */
901         BLI_freelistN(&anim_data);
902 }
903
904 /* ------------------- */
905
906 static int actkeys_handletype_exec(bContext *C, wmOperator *op)
907 {
908         bAnimContext ac;
909         short mode;
910         
911         /* get editor data */
912         if (ANIM_animdata_get_context(C, &ac) == 0)
913                 return OPERATOR_CANCELLED;
914         if (ac.datatype == ANIMCONT_GPENCIL) 
915                 return OPERATOR_PASS_THROUGH;
916                 
917         /* get handle setting mode */
918         mode= RNA_enum_get(op->ptr, "type");
919         
920         /* set handle type */
921         sethandles_action_keys(&ac, mode);
922         
923         /* validate keyframes after editing */
924         ANIM_editkeyframes_refresh(&ac);
925         
926         /* set notifier tha things have changed */
927         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
928         
929         return OPERATOR_FINISHED;
930 }
931  
932 void ACT_OT_keyframes_handletype (wmOperatorType *ot)
933 {
934         PropertyRNA *prop;
935         
936         /* identifiers */
937         ot->name= "Set Keyframe Handle Type";
938         ot->idname= "ACT_OT_keyframes_handletype";
939         
940         /* api callbacks */
941         ot->invoke= WM_menu_invoke;
942         ot->exec= actkeys_handletype_exec;
943         ot->poll= ED_operator_areaactive;
944         
945         /* flags */
946         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
947         
948         /* id-props */
949         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
950         RNA_def_property_enum_items(prop, prop_actkeys_handletype_types);
951 }
952
953 /* ************************************************************************** */
954 /* TRANSFORM STUFF */
955
956 /* ***************** Snap Current Frame Operator *********************** */
957
958 /* helper callback for actkeys_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
959 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
960 static short bezt_calc_average(BeztEditData *bed, BezTriple *bezt)
961 {
962         /* only if selected */
963         if (bezt->f2 & SELECT) {
964                 /* store average time in float (only do rounding at last step */
965                 bed->f1 += bezt->vec[1][0];
966                 
967                 /* increment number of items */
968                 bed->i1++;
969         }
970         
971         return 0;
972 }
973
974 /* snap current-frame indicator to 'average time' of selected keyframe */
975 static int actkeys_cfrasnap_exec(bContext *C, wmOperator *op)
976 {
977         bAnimContext ac;
978         ListBase anim_data= {NULL, NULL};
979         bAnimListElem *ale;
980         int filter;
981         BeztEditData bed;
982         
983         /* get editor data */
984         if (ANIM_animdata_get_context(C, &ac) == 0)
985                 return OPERATOR_CANCELLED;
986         
987         /* init edit data */
988         memset(&bed, 0, sizeof(BeztEditData));
989         
990         /* loop over action data, averaging values */
991         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_IPOKEYS);
992         ANIM_animdata_filter(&anim_data, filter, ac.data, ac.datatype);
993         
994         for (ale= anim_data.first; ale; ale= ale->next)
995                 ipo_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
996         
997         BLI_freelistN(&anim_data);
998         
999         /* set the new current frame value, based on the average time */
1000         if (bed.i1) {
1001                 Scene *scene= ac.scene;
1002                 CFRA= (int)floor((bed.f1 / bed.i1) + 0.5f);
1003         }
1004         
1005         /* set notifier tha things have changed */
1006         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene);
1007         
1008         return OPERATOR_FINISHED;
1009 }
1010
1011 void ACT_OT_keyframes_cfrasnap (wmOperatorType *ot)
1012 {
1013         /* identifiers */
1014         ot->name= "Snap Current Frame to Keys";
1015         ot->idname= "ACT_OT_keyframes_cfrasnap";
1016         
1017         /* api callbacks */
1018         ot->exec= actkeys_cfrasnap_exec;
1019         ot->poll= ED_operator_areaactive;
1020         
1021         /* flags */
1022         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
1023 }
1024
1025 /* ******************** Snap Keyframes Operator *********************** */
1026
1027 /* defines for snap keyframes tool */
1028 EnumPropertyItem prop_actkeys_snap_types[] = {
1029         {ACTKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
1030         {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
1031         {ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
1032         {ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
1033         {0, NULL, NULL, NULL}
1034 };
1035
1036 /* this function is responsible for snapping keyframes to frame-times */
1037 static void snap_action_keys(bAnimContext *ac, short mode) 
1038 {
1039         ListBase anim_data = {NULL, NULL};
1040         bAnimListElem *ale;
1041         int filter;
1042         
1043         BeztEditData bed;
1044         BeztEditFunc edit_cb;
1045         
1046         /* filter data */
1047         if (ac->datatype == ANIMCONT_GPENCIL)
1048                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
1049         else
1050                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
1051         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
1052         
1053         /* get beztriple editing callbacks */
1054         edit_cb= ANIM_editkeyframes_snap(mode);
1055         
1056         memset(&bed, 0, sizeof(BeztEditData)); 
1057         bed.scene= ac->scene;
1058         
1059         /* snap keyframes */
1060         for (ale= anim_data.first; ale; ale= ale->next) {
1061                 Object *nob= ANIM_nla_mapping_get(ac, ale);
1062                 
1063                 if (nob) {
1064                         ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1); 
1065                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
1066                         ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
1067                 }
1068                 //else if (ale->type == ACTTYPE_GPLAYER)
1069                 //      snap_gplayer_frames(ale->data, mode);
1070                 else 
1071                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
1072         }
1073         BLI_freelistN(&anim_data);
1074 }
1075
1076 /* ------------------- */
1077
1078 static int actkeys_snap_exec(bContext *C, wmOperator *op)
1079 {
1080         bAnimContext ac;
1081         short mode;
1082         
1083         /* get editor data */
1084         if (ANIM_animdata_get_context(C, &ac) == 0)
1085                 return OPERATOR_CANCELLED;
1086                 
1087         /* get snapping mode */
1088         mode= RNA_enum_get(op->ptr, "type");
1089         
1090         /* snap keyframes */
1091         snap_action_keys(&ac, mode);
1092         
1093         /* validate keyframes after editing */
1094         ANIM_editkeyframes_refresh(&ac);
1095         
1096         /* set notifier tha things have changed */
1097         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
1098         
1099         return OPERATOR_FINISHED;
1100 }
1101  
1102 void ACT_OT_keyframes_snap (wmOperatorType *ot)
1103 {
1104         PropertyRNA *prop;
1105         
1106         /* identifiers */
1107         ot->name= "Snap Keys";
1108         ot->idname= "ACT_OT_keyframes_snap";
1109         
1110         /* api callbacks */
1111         ot->invoke= WM_menu_invoke;
1112         ot->exec= actkeys_snap_exec;
1113         ot->poll= ED_operator_areaactive;
1114         
1115         /* flags */
1116         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
1117         
1118         /* id-props */
1119         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1120         RNA_def_property_enum_items(prop, prop_actkeys_snap_types);
1121 }
1122
1123 /* ******************** Mirror Keyframes Operator *********************** */
1124
1125 /* defines for mirror keyframes tool */
1126 EnumPropertyItem prop_actkeys_mirror_types[] = {
1127         {ACTKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
1128         {ACTKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
1129         {ACTKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
1130         {ACTKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
1131         {0, NULL, NULL, NULL}
1132 };
1133
1134 /* this function is responsible for mirroring keyframes */
1135 static void mirror_action_keys(bAnimContext *ac, short mode) 
1136 {
1137         ListBase anim_data = {NULL, NULL};
1138         bAnimListElem *ale;
1139         int filter;
1140         
1141         BeztEditData bed;
1142         BeztEditFunc edit_cb;
1143         
1144         /* get beztriple editing callbacks */
1145         edit_cb= ANIM_editkeyframes_mirror(mode);
1146         
1147         memset(&bed, 0, sizeof(BeztEditData)); 
1148         bed.scene= ac->scene;
1149         
1150         /* for 'first selected marker' mode, need to find first selected marker first! */
1151         // XXX should this be made into a helper func in the API?
1152         if (mode == ACTKEYS_MIRROR_MARKER) {
1153                 Scene *scene= ac->scene;
1154                 TimeMarker *marker= NULL;
1155                 
1156                 /* find first selected marker */
1157                 for (marker= scene->markers.first; marker; marker=marker->next) {
1158                         if (marker->flag & SELECT) {
1159                                 break;
1160                         }
1161                 }
1162                 
1163                 /* store marker's time (if available) */
1164                 if (marker)
1165                         bed.f1= marker->frame;
1166                 else
1167                         return;
1168         }
1169         
1170         /* filter data */
1171         if (ac->datatype == ANIMCONT_GPENCIL)
1172                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
1173         else
1174                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
1175         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
1176         
1177         /* mirror keyframes */
1178         for (ale= anim_data.first; ale; ale= ale->next) {
1179                 Object *nob= ANIM_nla_mapping_get(ac, ale);
1180                 
1181                 if (nob) {
1182                         ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1); 
1183                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
1184                         ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
1185                 }
1186                 //else if (ale->type == ACTTYPE_GPLAYER)
1187                 //      snap_gplayer_frames(ale->data, mode);
1188                 else 
1189                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
1190         }
1191         BLI_freelistN(&anim_data);
1192 }
1193
1194 /* ------------------- */
1195
1196 static int actkeys_mirror_exec(bContext *C, wmOperator *op)
1197 {
1198         bAnimContext ac;
1199         short mode;
1200         
1201         /* get editor data */
1202         if (ANIM_animdata_get_context(C, &ac) == 0)
1203                 return OPERATOR_CANCELLED;
1204                 
1205         /* get mirroring mode */
1206         mode= RNA_enum_get(op->ptr, "type");
1207         
1208         /* mirror keyframes */
1209         mirror_action_keys(&ac, mode);
1210         
1211         /* validate keyframes after editing */
1212         ANIM_editkeyframes_refresh(&ac);
1213         
1214         /* set notifier tha things have changed */
1215         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
1216         
1217         return OPERATOR_FINISHED;
1218 }
1219  
1220 void ACT_OT_keyframes_mirror (wmOperatorType *ot)
1221 {
1222         PropertyRNA *prop;
1223         
1224         /* identifiers */
1225         ot->name= "Mirror Keys";
1226         ot->idname= "ACT_OT_keyframes_mirror";
1227         
1228         /* api callbacks */
1229         ot->invoke= WM_menu_invoke;
1230         ot->exec= actkeys_mirror_exec;
1231         ot->poll= ED_operator_areaactive;
1232         
1233         /* flags */
1234         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
1235         
1236         /* id-props */
1237         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
1238         RNA_def_property_enum_items(prop, prop_actkeys_mirror_types);
1239 }
1240
1241 /* ************************************************************************** */