== Action/Pose Groups - Keyframing Integration ==
[blender.git] / source / blender / src / editaction.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): 2007, Joshua Leung (major rewrite of Action Editor)
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <string.h>
34 #include <stddef.h>
35 #include <math.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "PIL_time.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
43
44 #include "DNA_action_types.h"
45 #include "DNA_armature_types.h"
46 #include "DNA_curve_types.h"
47 #include "DNA_ipo_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_userdef_types.h"
53 #include "DNA_constraint_types.h"
54 #include "DNA_key_types.h"
55 #include "DNA_mesh_types.h"
56 #include "DNA_nla_types.h"
57 #include "DNA_lattice_types.h"
58
59 #include "BKE_action.h"
60 #include "BKE_armature.h"
61 #include "BKE_constraint.h"
62 #include "BKE_curve.h"
63 #include "BKE_depsgraph.h"
64 #include "BKE_global.h"
65 #include "BKE_ipo.h"
66 #include "BKE_key.h"
67 #include "BKE_library.h"
68 #include "BKE_main.h"
69 #include "BKE_utildefines.h"
70 #include "BKE_object.h" /* for where_is_object in obanim -> action baking */
71
72 #include "BIF_butspace.h"
73 #include "BIF_editaction.h"
74 #include "BIF_editarmature.h"
75 #include "BIF_editnla.h"
76 #include "BIF_editview.h"
77 #include "BIF_gl.h"
78 #include "BIF_interface.h"
79 #include "BIF_mywindow.h"
80 #include "BIF_poseobject.h"
81 #include "BIF_screen.h"
82 #include "BIF_space.h"
83 #include "BIF_toolbox.h"
84 #include "BIF_transform.h"
85
86 #include "BSE_edit.h"
87 #include "BSE_drawipo.h"
88 #include "BSE_headerbuttons.h"
89 #include "BSE_editaction_types.h"
90 #include "BSE_editipo.h"
91 #include "BSE_time.h"
92 #include "BSE_trans_types.h"
93
94 #include "BDR_drawaction.h"
95 #include "BDR_editobject.h"
96
97 #include "mydevice.h"
98 #include "blendef.h"
99 #include "nla.h"
100
101 /* **************************************************** */
102 /* ACTION API */
103
104 /* this function adds a new Action block */
105 bAction *add_empty_action (char *name)
106 {
107         bAction *act;
108         
109         act= alloc_libblock(&G.main->action, ID_AC, name);
110         act->id.flag |= LIB_FAKEUSER;
111         act->id.us++;
112         
113         return act;
114 }
115
116 /* generic get current action call, for action window context */
117 bAction *ob_get_action (Object *ob)
118 {
119         bActionStrip *strip;
120         
121         if(ob->action)
122                 return ob->action;
123         
124         for (strip=ob->nlastrips.first; strip; strip=strip->next) {
125                 if (strip->flag & ACTSTRIP_SELECT)
126                         return strip->act;
127         }
128         return NULL;
129 }
130
131 /* used by ipo, outliner, buttons to find the active channel */
132 bActionChannel *get_hilighted_action_channel (bAction *action)
133 {
134         bActionChannel *achan;
135
136         if (!action)
137                 return NULL;
138
139         for (achan= action->chanbase.first; achan; achan= achan->next) {
140                 if (VISIBLE_ACHAN(achan)) {
141                         if (SEL_ACHAN(achan) && (achan->flag & ACHAN_HILIGHTED))
142                                 return achan;
143                 }
144         }
145
146         return NULL;
147 }
148
149 /* ----------------------------------------- */
150
151 void remake_action_ipos (bAction *act)
152 {
153         bActionChannel *achan;
154         bConstraintChannel *conchan;
155         IpoCurve *icu;
156
157         for (achan= act->chanbase.first; achan; achan= achan->next) {
158                 if (achan->ipo) {
159                         for (icu = achan->ipo->curve.first; icu; icu=icu->next) {
160                                 sort_time_ipocurve(icu);
161                                 testhandles_ipocurve(icu);
162                         }
163                 }
164                 for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
165                         if (conchan->ipo) {
166                                 for (icu = conchan->ipo->curve.first; icu; icu=icu->next) {
167                                         sort_time_ipocurve(icu);
168                                         testhandles_ipocurve(icu);
169                                 }
170                         }
171                 }
172         }
173         
174         synchronize_action_strips();
175 }
176
177 /* **************************************************** */
178 /* FILTER->EDIT STRUCTURES */
179 /* 
180  * This method involves generating a list of edit structures which enable
181  * tools to naively perform the actions they require without all the boiler-plate
182  * associated with loops within loops and checking for cases to ignore. 
183  */
184
185 /* this function allocates memory for a new bActListElem struct for the 
186  * provided action channel-data. 
187  */
188 bActListElem *make_new_actlistelem (void *data, short datatype, void *owner, short ownertype)
189 {
190         bActListElem *ale= NULL;
191         
192         /* only allocate memory if there is data to convert */
193         if (data) {
194                 /* allocate and set generic data */
195                 ale= MEM_callocN(sizeof(bActListElem), "bActListElem");
196                 
197                 ale->data= data;
198                 ale->type= datatype;
199                 ale->owner= owner;
200                 ale->ownertype= ownertype;
201                 
202                 if ((owner) && (ownertype == ACTTYPE_ACHAN)) {
203                         bActionChannel *ochan= (bActionChannel *)owner;
204                         ale->grp= ochan->grp;
205                 }
206                 else 
207                         ale->grp= NULL;
208                 
209                 /* do specifics */
210                 switch (datatype) {
211                         case ACTTYPE_GROUP:
212                         {
213                                 bActionGroup *agrp= (bActionGroup *)data;
214                                 
215                                 ale->flag= agrp->flag;
216                                 
217                                 ale->key_data= NULL;
218                                 ale->datatype= ALE_GROUP;
219                         }
220                                 break;
221                         case ACTTYPE_ACHAN:
222                         {
223                                 bActionChannel *achan= (bActionChannel *)data;
224                                 
225                                 ale->flag= achan->flag;
226                                 
227                                 if (achan->ipo) {
228                                         ale->key_data= achan->ipo;
229                                         ale->datatype= ALE_IPO;
230                                 }
231                                 else {
232                                         ale->key_data= NULL;
233                                         ale->datatype= ALE_NONE;
234                                 }
235                         }       
236                                 break;
237                         case ACTTYPE_CONCHAN:
238                         {
239                                 bConstraintChannel *conchan= (bConstraintChannel *)data;
240                                 
241                                 ale->flag= conchan->flag;
242                                 
243                                 if (conchan->ipo && conchan->ipo->curve.first) {
244                                         /* we assume that constraint ipo blocks only have 1 curve:
245                                          * INFLUENCE, so we pretend that a constraint channel is 
246                                          * really just a Ipo-Curve channel instead.
247                                          */
248                                         ale->key_data= conchan->ipo->curve.first;
249                                         ale->datatype= ALE_ICU;
250                                 }
251                                 else {
252                                         ale->key_data= NULL;
253                                         ale->datatype= ALE_NONE;
254                                 }
255                         }
256                                 break;
257                         case ACTTYPE_ICU:
258                         {
259                                 IpoCurve *icu= (IpoCurve *)data;
260                                 
261                                 ale->flag= icu->flag;
262                                 ale->key_data= icu;
263                                 ale->datatype= ALE_ICU;
264                         }
265                                 break;
266                                 
267                         case ACTTYPE_FILLIPO:
268                         case ACTTYPE_FILLCON:
269                         {
270                                 bActionChannel *achan= (bActionChannel *)data;
271                                 
272                                 if (datatype == ACTTYPE_FILLIPO)
273                                         ale->flag= FILTER_IPO_ACHAN(achan);
274                                 else
275                                         ale->flag= FILTER_CON_ACHAN(achan);
276                                         
277                                 ale->key_data= NULL;
278                                 ale->datatype= ALE_NONE;
279                         }
280                                 break;
281                         case ACTTYPE_IPO:
282                         {
283                                 ale->flag= 0;
284                                 ale->key_data= data;
285                                 ale->datatype= ALE_IPO;
286                         }
287                                 break;
288                 }
289         }
290         
291         /* return created datatype */
292         return ale;
293 }
294  
295 /* ----------------------------------------- */
296  
297 static void actdata_filter_actionchannel (ListBase *act_data, bActionChannel *achan, int filter_mode)
298 {
299         bActListElem *ale;
300         bConstraintChannel *conchan;
301         IpoCurve *icu;
302         
303         /* only work with this channel and its subchannels if it is visible */
304         if (!(filter_mode & ACTFILTER_VISIBLE) || VISIBLE_ACHAN(achan)) {
305                 /* only work with this channel and its subchannels if it is editable */
306                 if (!(filter_mode & ACTFILTER_FOREDIT) || EDITABLE_ACHAN(achan)) {
307                         /* check if this achan should only be included if it is selected */
308                         if (!(filter_mode & ACTFILTER_SEL) || SEL_ACHAN(achan)) {
309                                 /* are we only interested in the ipo-curves? */
310                                 if ((filter_mode & ACTFILTER_ONLYICU)==0) {
311                                         ale= make_new_actlistelem(achan, ACTTYPE_ACHAN, achan, ACTTYPE_ACHAN);
312                                         if (ale) BLI_addtail(act_data, ale);
313                                 }
314                         }
315                         else {
316                                 /* only consider selected channels - achan not selected */
317                                 return;
318                         }       
319                         
320                         /* check if expanded - if not, continue on to next action channel */
321                         if (EXPANDED_ACHAN(achan) == 0 && (filter_mode & ACTFILTER_ONLYICU)==0) 
322                                 return;
323                                 
324                         /* ipo channels */
325                         if (achan->ipo) {
326                                 /* include ipo-expand widget? */
327                                 if ((filter_mode & ACTFILTER_CHANNELS) && (filter_mode & ACTFILTER_ONLYICU)==0) {
328                                         ale= make_new_actlistelem(achan, ACTTYPE_FILLIPO, achan, ACTTYPE_ACHAN);
329                                         if (ale) BLI_addtail(act_data, ale);
330                                 }
331                                 
332                                 /* add ipo-curve channels? */
333                                 if (FILTER_IPO_ACHAN(achan) || (filter_mode & ACTFILTER_ONLYICU)) {
334                                         /* loop through ipo-curve channels, adding them */
335                                         for (icu= achan->ipo->curve.first; icu; icu=icu->next) {
336                                                 ale= make_new_actlistelem(icu, ACTTYPE_ICU, achan, ACTTYPE_ACHAN);
337                                                 if (ale) BLI_addtail(act_data, ale); 
338                                         }
339                                 }
340                         }
341                         
342                         /* constraint channels */
343                         if (achan->constraintChannels.first) {
344                                 /* include constraint-expand widget? */
345                                 if ((filter_mode & ACTFILTER_CHANNELS) && (filter_mode & ACTFILTER_ONLYICU)==0) {
346                                         ale= make_new_actlistelem(achan, ACTTYPE_FILLCON, achan, ACTTYPE_ACHAN);
347                                         if (ale) BLI_addtail(act_data, ale);
348                                 }
349                                 
350                                 /* add constaint channels? */
351                                 if (FILTER_CON_ACHAN(achan)) {
352                                         /* loop through constraint channels, checking and adding them */
353                                         for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
354                                                 /* only work with this channel and its subchannels if it is editable */
355                                                 if (!(filter_mode & ACTFILTER_FOREDIT) || EDITABLE_CONCHAN(conchan)) {
356                                                         /* check if this conchan should only be included if it is selected */
357                                                         if (!(filter_mode & ACTFILTER_SEL) || SEL_CONCHAN(conchan)) {
358                                                                 if ((filter_mode & ACTFILTER_ONLYICU)==0) {
359                                                                         ale= make_new_actlistelem(conchan, ACTTYPE_CONCHAN, achan, ACTTYPE_ACHAN);
360                                                                         if (ale) BLI_addtail(act_data, ale); 
361                                                                 }
362                                                         }
363                                                 }
364                                         }
365                                 }
366                         }
367                 }               
368         }
369 }
370
371 static void actdata_filter_action (ListBase *act_data, bAction *act, int filter_mode)
372 {
373         bActListElem *ale;
374         bActionGroup *agrp;
375         bActionChannel *achan, *lastchan=NULL;
376         
377         /* loop over groups */
378         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
379                 /* add this group as a channel first */
380                 if (!(filter_mode & ACTFILTER_ONLYICU) && !(filter_mode & ACTFILTER_IPOKEYS)) {
381                         ale= make_new_actlistelem(agrp, ACTTYPE_GROUP, NULL, ACTTYPE_NONE);
382                         if (ale) BLI_addtail(act_data, ale);
383                 }
384                 
385                 /* store reference to last channel of group */
386                 if (agrp->channels.last) 
387                         lastchan= agrp->channels.last;
388                 
389                 /* filters here are a bit convulted...
390                  *      - groups show a "summary" of keyframes beside their name which must accessable for tools which handle keyframes
391                  *      - groups can be collapsed (and those tools which are only interested in channels rely on knowing that group is closed)
392                  */
393                 if (!(filter_mode & ACTFILTER_VISIBLE) || EXPANDED_AGRP(agrp) || 
394                         (filter_mode & (ACTFILTER_IPOKEYS|ACTFILTER_ONLYICU))) 
395                 {
396                         if (!(filter_mode & ACTFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {                                        
397                                 for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
398                                         actdata_filter_actionchannel(act_data, achan, filter_mode);
399                                 }
400                         }
401                 }
402         }
403         
404         /* loop over action channels */
405         for (achan=(lastchan)?lastchan->next:act->chanbase.first; achan; achan=achan->next) {
406                 actdata_filter_actionchannel(act_data, achan, filter_mode);
407         }
408 }
409
410 static void actdata_filter_shapekey (ListBase *act_data, Key *key, int filter_mode)
411 {
412         bActListElem *ale;
413         KeyBlock *kb;
414         IpoCurve *icu;
415         int i;
416         
417         /* are we filtering for display or editing */
418         if (filter_mode & ACTFILTER_FORDRAWING) {
419                 /* for display - loop over shapekeys, adding ipo-curve references where needed */
420                 kb= key->block.first;
421                 
422                 /* loop through possible shapekeys, manually creating entries */
423                 for (i= 1; i < key->totkey; i++) {
424                         ale= MEM_callocN(sizeof(bActListElem), "bActListElem");
425                         kb = kb->next;
426                         
427                         ale->data= kb;
428                         ale->type= ACTTYPE_SHAPEKEY; /* 'abused' usage of this type */
429                         ale->owner= key;
430                         ale->ownertype= ACTTYPE_SHAPEKEY;
431                         ale->datatype= ALE_NONE;
432                         ale->index = i;
433                         
434                         if (key->ipo) {
435                                 for (icu= key->ipo->curve.first; icu; icu=icu->next) {
436                                         if (icu->adrcode == i) {
437                                                 ale->key_data= icu;
438                                                 ale->datatype= ALE_ICU;
439                                                 break;
440                                         }
441                                 }
442                         }
443                         
444                         BLI_addtail(act_data, ale);
445                 }
446         }
447         else {
448                 /* loop over ipo curves if present - for editing */
449                 if (key->ipo) {
450                         if (filter_mode & ACTFILTER_IPOKEYS) {
451                                 ale= make_new_actlistelem(key->ipo, ACTTYPE_IPO, key, ACTTYPE_SHAPEKEY);
452                                 if (ale) BLI_addtail(act_data, ale);
453                         }
454                         else {
455                                 for (icu= key->ipo->curve.first; icu; icu=icu->next) {
456                                         ale= make_new_actlistelem(icu, ACTTYPE_ICU, key, ACTTYPE_SHAPEKEY);
457                                         if (ale) BLI_addtail(act_data, ale);
458                                 }
459                         }
460                 }
461         }
462 }
463  
464 /* This function filters the active data source to leave only the desired
465  * data types. 'Public' api call.
466  *      *act_data: is a pointer to a ListBase, to which the filtered action data 
467  *              will be placed for use.
468  *      filter_mode: how should the data be filtered - bitmapping accessed flags
469  */
470 void actdata_filter (ListBase *act_data, int filter_mode, void *data, short datatype)
471 {
472         /* only filter data if there's somewhere to put it */
473         if (data && act_data) {
474                 bActListElem *ale, *next;
475                 
476                 /* firstly filter the data */
477                 switch (datatype) {
478                         case ACTCONT_ACTION:
479                                 actdata_filter_action(act_data, data, filter_mode);
480                                 break;
481                         case ACTCONT_SHAPEKEY:
482                                 actdata_filter_shapekey(act_data, data, filter_mode);
483                                 break;
484                 }
485                         
486                 /* remove any weedy entries */
487                 for (ale= act_data->first; ale; ale= next) {
488                         next= ale->next;
489                         
490                         if (ale->type == ACTTYPE_NONE)
491                                 BLI_freelinkN(act_data, ale);
492                         
493                         if (filter_mode & ACTFILTER_IPOKEYS) {
494                                 if (ale->datatype != ALE_IPO)
495                                         BLI_freelinkN(act_data, ale);
496                                 else if (ale->key_data == NULL)
497                                         BLI_freelinkN(act_data, ale);
498                         }
499                 }
500         }
501 }
502
503 /* **************************************************** */
504 /* GENERAL ACTION TOOLS */
505
506 /* gets the key data from the currently selected
507  * mesh/lattice. If a mesh is not selected, or does not have
508  * key data, then we return NULL (currently only
509  * returns key data for RVK type meshes). If there
510  * is an action that is pinned, return null
511  */
512 /* Note: there's a similar function in key.c (ob_get_key) */
513 Key *get_action_mesh_key(void) 
514 {
515     Object *ob;
516     Key    *key;
517
518     ob = OBACT;
519     if (ob == NULL) 
520                 return NULL;
521
522         if (G.saction->pin) return NULL;
523
524     if (ob->type==OB_MESH) 
525                 key = ((Mesh *)ob->data)->key;
526         else if (ob->type==OB_LATTICE) 
527                 key = ((Lattice *)ob->data)->key;
528         else 
529                 return NULL;
530
531         if (key) {
532                 if (key->type == KEY_RELATIVE)
533                         return key;
534         }
535
536     return NULL;
537 }
538
539 /* TODO: kill this! */
540 int get_nearest_key_num (Key *key, short *mval, float *x) 
541 {
542         /* returns the key num that cooresponds to the
543          * y value of the mouse click. Does not check
544          * if this is a valid keynum. Also gives the Ipo
545          * x coordinate.
546          */
547     int num;
548     float y;
549
550     areamouseco_to_ipoco(G.v2d, mval, x, &y);
551     num = (int) ((CHANNELHEIGHT/2 - y) / (CHANNELHEIGHT+CHANNELSKIP));
552
553     return (num + 1);
554 }
555
556 /* this function is used to get a pointer to an action or shapekey 
557  * datablock, thus simplying that process.
558  */
559 /* this function is intended for use */
560 void *get_nearest_act_channel (short mval[], short *ret_type)
561 {
562         ListBase act_data = {NULL, NULL};
563         bActListElem *ale;
564         void *data;
565         short datatype;
566         int filter;
567         
568         int clickmin, clickmax;
569         float x,y;
570         
571         /* determine what type of data we are operating on */
572         data = get_action_context(&datatype);
573         if (data == NULL) {
574                 *ret_type= ACTTYPE_NONE;
575                 return NULL;
576         }
577         
578     areamouseco_to_ipoco(G.v2d, mval, &x, &y);
579         clickmin = (int) (((CHANNELHEIGHT/2) - y) / (CHANNELHEIGHT+CHANNELSKIP));
580         clickmax = clickmin;
581         
582         if (clickmax < 0) {
583                 *ret_type= ACTTYPE_NONE;
584                 return NULL;
585         }
586         
587         /* filter data */
588         filter= (ACTFILTER_FORDRAWING | ACTFILTER_VISIBLE | ACTFILTER_CHANNELS);
589         actdata_filter(&act_data, filter, data, datatype);
590         
591         for (ale= act_data.first; ale; ale= ale->next) {
592                 if (clickmax < 0) 
593                         break;
594                 if (clickmin <= 0) {
595                         /* found match */
596                         *ret_type= ale->type;
597                         data= ale->data;
598                         
599                         BLI_freelistN(&act_data);
600                         
601                         return data;
602                 }
603                 --clickmin;
604                 --clickmax;
605         }
606         
607         /* cleanup */
608         BLI_freelistN(&act_data);
609         
610         *ret_type= ACTTYPE_NONE;
611         return NULL;
612 }
613
614 /* used only by mouse_action. It is used to find the location of the nearest 
615  * keyframe to where the mouse clicked, 
616  */
617 static void *get_nearest_action_key (float *selx, short *sel, short *ret_type, bActionChannel **par)
618 {
619         ListBase act_data = {NULL, NULL};
620         ListBase act_keys = {NULL, NULL};
621         bActListElem *ale;
622         ActKeyColumn *ak;
623         void *data;
624         short datatype;
625         int filter;
626         
627         rctf rectf;
628         float xmin, xmax, x, y;
629         int clickmin, clickmax;
630         short mval[2];
631         short found = 0;
632                 
633         getmouseco_areawin (mval);
634
635         /* action-channel */
636         *par= NULL;
637         
638         /* determine what type of data we are operating on */
639         data = get_action_context(&datatype);
640         if (data == NULL) {
641                 *ret_type= ACTTYPE_NONE;
642                 return NULL;
643         }
644
645     areamouseco_to_ipoco(G.v2d, mval, &x, &y);
646     clickmin = (int) (((CHANNELHEIGHT/2) - y) / (CHANNELHEIGHT+CHANNELSKIP));
647         clickmax = clickmin;
648         
649         mval[0]-=7;
650         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
651         mval[0]+=14;
652         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
653
654         /* if action is mapped in NLA, it returns a correction */
655         if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
656                 xmin= get_action_frame(OBACT, rectf.xmin);
657                 xmax= get_action_frame(OBACT, rectf.xmax);
658         }
659         else {
660                 xmin= rectf.xmin;
661                 xmax= rectf.xmax;
662         }
663         
664         if (clickmax < 0) {
665                 *ret_type= ACTTYPE_NONE;
666                 return NULL;
667         }
668                 
669         /* filter data */
670         filter= (ACTFILTER_FORDRAWING | ACTFILTER_VISIBLE | ACTFILTER_CHANNELS);
671         actdata_filter(&act_data, filter, data, datatype);
672         
673         for (ale= act_data.first; ale; ale= ale->next) {
674                 if (clickmax < 0) 
675                         break;
676                 if (clickmin <= 0) {
677                         /* found match */
678                         
679                         /* make list of keyframes */
680                         if (ale->key_data) {
681                                 switch (ale->datatype) {
682                                         case ALE_IPO:
683                                         {
684                                                 Ipo *ipo= (Ipo *)ale->key_data;
685                                                 ipo_to_keylist(ipo, &act_keys, NULL);
686                                         }
687                                                 break;
688                                         case ALE_ICU:
689                                         {
690                                                 IpoCurve *icu= (IpoCurve *)ale->key_data;
691                                                 icu_to_keylist(icu, &act_keys, NULL);
692                                         }
693                                                 break;
694                                 }
695                         }
696                         else if (ale->type == ACTTYPE_GROUP) {
697                                 bActionGroup *agrp= (bActionGroup *)ale->data;
698                                 agroup_to_keylist(agrp, &act_keys, NULL);
699                         }
700                         
701                         /* loop through keyframes, finding one that was clicked on */
702                         for (ak= act_keys.first; ak; ak= ak->next) {
703                                 if (IN_RANGE(ak->cfra, xmin, xmax)) {
704                                         *selx= ak->cfra;
705                                         found= 1;
706                                         break;
707                                 }
708                         }
709                         /* no matching keyframe found - set to mean frame value so it doesn't actually select anything */
710                         if (found == 0)
711                                 *selx= ((xmax+xmin) / 2);
712                         
713                         /* figure out what to return */
714                         if (datatype == ACTCONT_ACTION) {
715                                 *par= ale->owner; /* assume that this is an action channel */
716                                 *ret_type= ale->type;
717                                 data = ale->data;
718                         }
719                         else if (datatype == ACTCONT_SHAPEKEY) {
720                                 data = ale->key_data;
721                                 *ret_type= ACTTYPE_ICU;
722                         }
723                         
724                         /* cleanup tempolary lists */
725                         BLI_freelistN(&act_keys);
726                         act_keys.first = act_keys.last = NULL;
727                         
728                         BLI_freelistN(&act_data);
729                         
730                         return data;
731                 }
732                 --clickmin;
733                 --clickmax;
734         }
735         
736         /* cleanup */
737         BLI_freelistN(&act_data);
738         
739         *ret_type= ACTTYPE_NONE;
740         return NULL;
741 }
742
743 void *get_action_context (short *datatype)
744 {
745         bAction *act;
746         Key *key;
747         
748         /* get pointers to active action/shapekey blocks */
749         act = (G.saction)? G.saction->action: NULL;
750         key = get_action_mesh_key();
751         
752         if (act) {
753                 *datatype= ACTCONT_ACTION;
754                 return act;
755         }
756         else if (key) {
757                 *datatype= ACTCONT_SHAPEKEY;
758                 return key;
759         }
760         else {
761                 *datatype= ACTCONT_NONE;
762                 return NULL;
763         }
764 }
765
766 /* **************************************************** */
767 /* ACTION CHANNEL GROUPS */
768
769 /* Get the active action-group for an Action */
770 bActionGroup *get_active_actiongroup (bAction *act)
771 {
772         bActionGroup *agrp= NULL;
773         
774         if (act && act->groups.first) { 
775                 for (agrp= act->groups.first; agrp; agrp= agrp->next) {
776                         if (agrp->flag & AGRP_ACTIVE)
777                                 break;
778                 }
779         }
780         
781         return agrp;
782 }
783
784 /* Make the given Action-Group the active one */
785 void set_active_actiongroup (bAction *act, bActionGroup *agrp, short select)
786 {
787         bActionGroup *grp;
788         
789         /* sanity checks */
790         if (act == NULL)
791                 return;
792         
793         /* Deactive all others */
794         for (grp= act->groups.first; grp; grp= grp->next) {
795                 if ((grp==agrp) && (select))
796                         grp->flag |= AGRP_ACTIVE;
797                 else    
798                         grp->flag &= ~AGRP_ACTIVE;
799         }
800 }
801
802 /* Add given channel into (active) group 
803  *      - assumes that channel is not linked to anything anymore
804  *      - always adds at the end of the group 
805  */
806 static void action_groups_addachan (bAction *act, bActionGroup *agrp, bActionChannel *achan)
807 {
808         bActionChannel *chan;
809         short done=0;
810         
811         /* sanity checks */
812         if (ELEM3(NULL, act, agrp, achan))
813                 return;
814         
815         /* if no channels, just add to two lists at the same time */
816         if (act->chanbase.first == NULL) {
817                 achan->next = achan->prev = NULL;
818                 
819                 agrp->channels.first = agrp->channels.last = achan;
820                 act->chanbase.first = act->chanbase.last = achan;
821                 
822                 achan->grp= agrp;
823                 return;
824         }
825         
826         /* try to find a channel to slot this in before/after */
827         for (chan= act->chanbase.first; chan; chan= chan->next) {
828                 /* if channel has no group, then we have ungrouped channels, which should always occur after groups */
829                 if (chan->grp == NULL) {
830                         BLI_insertlinkbefore(&act->chanbase, chan, achan);
831                         
832                         if (agrp->channels.first == NULL)
833                                 agrp->channels.first= achan;
834                         agrp->channels.last= achan;
835                         
836                         done= 1;
837                         break;
838                 }
839                 
840                 /* if channel has group after current, we can now insert (otherwise we have gone too far) */
841                 else if (chan->grp == agrp->next) {
842                         BLI_insertlinkbefore(&act->chanbase, chan, achan);
843                         
844                         if (agrp->channels.first == NULL)
845                                 agrp->channels.first= achan;
846                         agrp->channels.last= achan;
847                         
848                         done= 1;
849                         break;
850                 }
851                 
852                 /* if channel has group we're targeting, check whether it is the last one of these */
853                 else if (chan->grp == agrp) {
854                         if ((chan->next) && (chan->next->grp != agrp)) {
855                                 BLI_insertlinkafter(&act->chanbase, chan, achan);
856                                 agrp->channels.last= achan;
857                                 done= 1;
858                                 break;
859                         }
860                         else if (chan->next == NULL) {
861                                 BLI_addtail(&act->chanbase, achan);
862                                 agrp->channels.last= achan;
863                                 done= 1;
864                                 break;
865                         }
866                 }
867                 
868                 /* if channel has group before target, check whether the next one is something after target */
869                 else if (chan->grp == agrp->prev) {
870                         if (chan->next) {
871                                 if ((chan->next->grp != chan->grp) && (chan->next->grp != agrp)) {
872                                         BLI_insertlinkafter(&act->chanbase, chan, achan);
873                                         
874                                         agrp->channels.first= achan;
875                                         agrp->channels.last= achan;
876                                         
877                                         done= 1;
878                                         break;
879                                 }
880                         }
881                         else {
882                                 BLI_insertlinkafter(&act->chanbase, chan, achan);
883                                         
884                                 agrp->channels.first= achan;
885                                 agrp->channels.last= achan;
886                                 
887                                 done= 1;
888                                 break;
889                         }
890                 }
891         }
892         
893         /* only if added, set channel as belonging to this group */
894         if (done) {
895                 achan->grp= agrp;
896         }
897         else 
898                 printf("Error: ActionChannel: '%s' couldn't be added to Group: '%s' \n", achan->name, agrp->name);
899 }       
900
901 /* Remove the given channel from all groups */
902 static void action_groups_removeachan (bAction *act, bActionChannel *achan)
903 {
904         /* sanity checks */
905         if (ELEM(NULL, act, achan))     
906                 return;
907         
908         /* check if any group used this directly */
909         if (achan->grp) {
910                 bActionGroup *agrp= achan->grp;
911                 
912                 if (agrp->channels.first == agrp->channels.last) {
913                         if (agrp->channels.first == achan) {
914                                 agrp->channels.first= NULL;
915                                 agrp->channels.last= NULL;
916                         }
917                 }
918                 else if (agrp->channels.first == achan) {
919                         if ((achan->next) && (achan->next->grp==agrp))
920                                 agrp->channels.first= achan->next;
921                         else
922                                 agrp->channels.first= NULL;
923                 }
924                 else if (agrp->channels.last == achan) {
925                         if ((achan->prev) && (achan->prev->grp==agrp))
926                                 agrp->channels.last= achan->prev;
927                         else
928                                 agrp->channels.last= NULL;
929                 }
930                 
931                 achan->grp= NULL;
932         }
933         
934         /* now just remove from list */
935         BLI_remlink(&act->chanbase, achan);
936 }
937
938 /* Add a new Action-Group or add channels to active one */
939 void action_groups_group (short add_group)
940 {
941         bAction *act;
942         bActionChannel *achan, *anext;
943         bActionGroup *agrp;
944         void *data;
945         short datatype;
946         
947         /* validate type of data we are working on */
948         data = get_action_context(&datatype);
949         if (data == NULL) return;
950         if (datatype != ACTCONT_ACTION) return;
951         act= (bAction *)data;
952         
953         /* get active group */
954         if ((act->groups.first==NULL) || (add_group)) {         
955                 /* Add a new group, and make it active */
956                 agrp= MEM_callocN(sizeof(bActionGroup), "bActionGroup");
957                 
958                 agrp->flag |= (AGRP_ACTIVE|AGRP_SELECTED|AGRP_EXPANDED);
959                 sprintf(agrp->name, "Group");
960                 
961                 BLI_addtail(&act->groups, agrp);
962                 BLI_uniquename(&act->groups, agrp, "Group", offsetof(bActionGroup, name), 32);
963                 
964                 set_active_actiongroup(act, agrp, 1);
965                 
966                 add_group= 1;
967         }
968         else {
969                 agrp= get_active_actiongroup(act);
970                 
971                 if (agrp == NULL) {
972                         error("No Active Action Group");
973                         return;
974                 }
975         }
976         
977         /* loop through action-channels, finding those that are selected + visible to move */
978         // FIXME: this should be done with action api instead 
979         for (achan= act->chanbase.first; achan; achan= anext) {
980                 anext= achan->next;
981                 
982                 /* make sure not already in new-group */
983                 if (achan->grp != agrp) {
984                         if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan)) {
985                                 /* unlink from everything else */
986                                 action_groups_removeachan(act, achan);
987                                 
988                                 /* add to end of group's channels */
989                                 action_groups_addachan(act, agrp, achan);
990                         }
991                 }
992         }
993         
994         /* updates and undo */
995         if (add_group)
996                 BIF_undo_push("Add Action Group");
997         else
998                 BIF_undo_push("Add to Action Group");
999         
1000         allqueue(REDRAWACTION, 0);
1001 }
1002
1003 /* Remove selected channels from their groups */
1004 void action_groups_ungroup (void)
1005 {
1006         ListBase act_data = {NULL, NULL};
1007         bActListElem *ale;
1008         bAction *act;
1009         void *data;
1010         short datatype;
1011         short filter;
1012         
1013         /* validate type of data we are working on */
1014         data = get_action_context(&datatype);
1015         if (data == NULL) return;
1016         if (datatype != ACTCONT_ACTION) return;
1017         act= (bAction *)data;
1018         
1019         /* filter data */
1020         filter= (ACTFILTER_VISIBLE|ACTFILTER_SEL);
1021         actdata_filter(&act_data, filter, act, ACTCONT_ACTION);
1022         
1023         /* Only ungroup selected action-channels */
1024         for (ale= act_data.first; ale; ale= ale->next) {
1025                 if (ale->type == ACTTYPE_ACHAN) {
1026                         action_groups_removeachan(act, ale->data);
1027                         BLI_addtail(&act->chanbase, ale->data);
1028                 }
1029         }
1030         
1031         BLI_freelistN(&act_data);
1032                 
1033         /* updates and undo */
1034         BIF_undo_push("Remove From Action Groups");
1035         
1036         allqueue(REDRAWACTION, 0);
1037 }
1038
1039 /* This function is used when inserting keyframes for pose-channels. It assigns the
1040  * action-channel with the nominated name to a group with the same name as that of 
1041  * the pose-channel with the nominated name.
1042  *
1043  * Note: this function calls validate_action_channel if action channel doesn't exist 
1044  */
1045 void verify_pchan2achan_grouping (bAction *act, bPose *pose, char name[])
1046 {
1047         bActionChannel *achan;
1048         bPoseChannel *pchan;
1049         
1050         /* sanity checks */
1051         if (ELEM3(NULL, act, pose, name))
1052                 return;
1053         if (name[0] == 0)
1054                 return;
1055                 
1056         /* try to get the channels */
1057         pchan= get_pose_channel(pose, name);
1058         if (pchan == NULL) return;
1059         achan= verify_action_channel(act, name);
1060         
1061         /* check if pchan has a group */
1062         if ((pchan->agrp_index) && (achan->grp == NULL)) {
1063                 bActionGroup *agrp, *grp=NULL;
1064                 
1065                 /* get group to try to be like */
1066                 agrp= (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1));
1067                 if (agrp == NULL) {
1068                         error("PoseChannel has invalid group!");
1069                         return;
1070                 }
1071                 
1072                 /* try to find a group which is similar to the one we want (or add one) */
1073                 for (grp= act->groups.first; grp; grp= grp->next) {
1074                         if (!strcmp(grp->name, agrp->name))
1075                                 break;
1076                 }
1077                 if (grp == NULL) {
1078                         grp= MEM_callocN(sizeof(bActionGroup), "bActionGroup");
1079                         
1080                         grp->flag |= (AGRP_ACTIVE|AGRP_SELECTED|AGRP_EXPANDED);
1081                         sprintf(grp->name, agrp->name);
1082                         
1083                         BLI_addtail(&act->groups, grp);
1084                 }
1085                 
1086                 /* make sure this channel is definitely not connected to anything before adding to group */
1087                 action_groups_removeachan(act, achan);
1088                 action_groups_addachan(act, grp, achan);
1089         }
1090 }
1091
1092 /* **************************************************** */
1093 /* TRANSFORM TOOLS */
1094
1095 /* main call to start transforming keyframes */
1096 void transform_action_keys (int mode, int dummy)
1097 {
1098         void *data;
1099         short datatype;
1100         
1101         /* determine what type of data we are operating on */
1102         data = get_action_context(&datatype);
1103         if (data == NULL) return;
1104         
1105         switch (mode) {
1106                 case 'g':
1107                 {
1108                         initTransform(TFM_TIME_TRANSLATE, CTX_NONE);
1109                         Transform();
1110                 }
1111                         break;
1112                 case 's':
1113                 {
1114                         initTransform(TFM_TIME_SCALE, CTX_NONE);
1115                         Transform();
1116                 }
1117                         break;
1118                 case 't':
1119                 {
1120                         initTransform(TFM_TIME_SLIDE, CTX_NONE);
1121                         Transform();
1122                 }
1123                         break;
1124                 case 'e':
1125                 {
1126                         initTransform(TFM_TIME_EXTEND, CTX_NONE);
1127                         Transform();
1128                 }
1129                 break;
1130         }
1131 }
1132
1133 /* ----------------------------------------- */
1134
1135 /* duplicate keyframes */
1136 void duplicate_action_keys (void)
1137 {
1138         ListBase act_data = {NULL, NULL};
1139         bActListElem *ale;
1140         void *data;
1141         short datatype;
1142         int filter;
1143         
1144         /* determine what type of data we are operating on */
1145         data = get_action_context(&datatype);
1146         if (data == NULL) return;
1147         
1148         /* filter data */
1149         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
1150         actdata_filter(&act_data, filter, data, datatype);
1151         
1152         /* loop through filtered data and duplicate selected keys */
1153         for (ale= act_data.first; ale; ale= ale->next) {
1154                 duplicate_ipo_keys((Ipo *)ale->key_data);
1155         }
1156         
1157         /* free filtered list */
1158         BLI_freelistN(&act_data);
1159         
1160         /* now, go into transform-grab mode, to move keys */
1161         transform_action_keys('g', 0);
1162 }
1163
1164 /* this function is responsible for snapping the current frame to selected data  */
1165 void snap_cfra_action() 
1166 {
1167         ListBase act_data = {NULL, NULL};
1168         bActListElem *ale;
1169         int filter;
1170         void *data;
1171         short datatype;
1172                 
1173         /* get data */
1174         data= get_action_context(&datatype);
1175         if (data == NULL) return;
1176         
1177         /* filter data */
1178         filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
1179         actdata_filter(&act_data, filter, data, datatype);
1180         
1181         /* snap current frame to selected data */
1182         snap_cfra_ipo_keys(NULL, -1);
1183         
1184         for (ale= act_data.first; ale; ale= ale->next) {
1185                 if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
1186                         actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1); 
1187                         snap_cfra_ipo_keys(ale->key_data, 0);
1188                         actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
1189                 }
1190                 else 
1191                         snap_cfra_ipo_keys(ale->key_data, 0);
1192         }
1193         BLI_freelistN(&act_data);
1194         
1195         snap_cfra_ipo_keys(NULL, 1);
1196         
1197         BIF_undo_push("Snap Current Frame to Keys");
1198         allqueue(REDRAWACTION, 0);
1199         allqueue(REDRAWIPO, 0);
1200         allqueue(REDRAWNLA, 0);
1201 }
1202
1203 /* this function is responsible for snapping keyframes to frame-times */
1204 void snap_action_keys(short mode) 
1205 {
1206         ListBase act_data = {NULL, NULL};
1207         bActListElem *ale;
1208         int filter;
1209         void *data;
1210         short datatype;
1211         char str[32];
1212                 
1213         /* get data */
1214         data= get_action_context(&datatype);
1215         if (data == NULL) return;
1216         
1217         /* determine mode */
1218         switch (mode) {
1219                 case 1:
1220                         strcpy(str, "Snap Keys To Nearest Frame");
1221                         break;
1222                 case 2:
1223                         if (G.saction->flag & SACTION_DRAWTIME)
1224                                 strcpy(str, "Snap Keys To Current Time");
1225                         else
1226                                 strcpy(str, "Snap Keys To Current Frame");
1227                         break;
1228                 case 3:
1229                         strcpy(str, "Snap Keys To Nearest Marker");
1230                         break;
1231                 case 4:
1232                         strcpy(str, "Snap Keys To Nearest Second");
1233                         break;
1234                 default:
1235                         return;
1236         }
1237         
1238         /* filter data */
1239         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
1240         actdata_filter(&act_data, filter, data, datatype);
1241         
1242         /* snap to frame */
1243         for (ale= act_data.first; ale; ale= ale->next) {
1244                 if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
1245                         actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1); 
1246                         snap_ipo_keys(ale->key_data, mode);
1247                         actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
1248                 }
1249                 else 
1250                         snap_ipo_keys(ale->key_data, mode);
1251         }
1252         BLI_freelistN(&act_data);
1253         
1254         if (datatype == ACTCONT_ACTION)
1255                 remake_action_ipos(data);
1256         
1257         BIF_undo_push(str);
1258         allspace(REMAKEIPO, 0);
1259         allqueue(REDRAWACTION, 0);
1260         allqueue(REDRAWIPO, 0);
1261         allqueue(REDRAWNLA, 0);
1262 }
1263
1264 /* this function is responsible for snapping keyframes to frame-times */
1265 void mirror_action_keys(short mode) 
1266 {
1267         ListBase act_data = {NULL, NULL};
1268         bActListElem *ale;
1269         int filter;
1270         void *data;
1271         short datatype;
1272         char str[32];
1273                 
1274         /* get data */
1275         data= get_action_context(&datatype);
1276         if (data == NULL) return;
1277         
1278         /* determine mode */
1279         switch (mode) {
1280                 case 1:
1281                         strcpy(str, "Mirror Keys Over Current Frame");
1282                         break;
1283                 case 2:
1284                         strcpy(str, "Mirror Keys Over Y-Axis");
1285                         break;
1286                 case 3:
1287                         strcpy(str, "Mirror Keys Over X-Axis");
1288                         break;
1289                 case 4:
1290                         strcpy(str, "Mirror Keys Over Marker");
1291                         break;
1292                 default:
1293                         return;
1294         }
1295         
1296         /* filter data */
1297         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
1298         actdata_filter(&act_data, filter, data, datatype);
1299         
1300         /* mirror */
1301         for (ale= act_data.first; ale; ale= ale->next) {
1302                 if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
1303                         actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1); 
1304                         mirror_ipo_keys(ale->key_data, mode);
1305                         actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
1306                 }
1307                 else 
1308                         mirror_ipo_keys(ale->key_data, mode);
1309         }
1310         BLI_freelistN(&act_data);
1311         
1312         if (datatype == ACTCONT_ACTION)
1313                 remake_action_ipos(data);
1314         
1315         BIF_undo_push(str);
1316         allspace(REMAKEIPO, 0);
1317         allqueue(REDRAWACTION, 0);
1318         allqueue(REDRAWIPO, 0);
1319         allqueue(REDRAWNLA, 0);
1320 }
1321
1322 /* **************************************************** */
1323 /* ADD/REMOVE KEYFRAMES */
1324
1325 /* This function allows the user to insert keyframes on the current
1326  * frame from the Action Editor, using the current values of the channels
1327  * to be keyframed.  
1328  */
1329 void insertkey_action(void)
1330 {
1331         void *data;
1332         short datatype;
1333         
1334         Object *ob= OBACT;
1335         short mode;
1336         float cfra;
1337         
1338         /* get data */
1339         data= get_action_context(&datatype);
1340         if (data == NULL) return;
1341         cfra = frame_to_float(CFRA);
1342                 
1343         if (datatype == ACTCONT_ACTION) {
1344                 ListBase act_data = {NULL, NULL};
1345                 bActListElem *ale;
1346                 int filter;
1347                 
1348                 /* ask user what to keyframe */
1349                 mode = pupmenu("Insert Key%t|All Channels%x1|Only Selected Channels%x2");
1350                 if (mode <= 0) return;
1351                 
1352                 /* filter data */
1353                 filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_ONLYICU );
1354                 if (mode == 2) filter |= ACTFILTER_SEL;
1355                 
1356                 actdata_filter(&act_data, filter, data, datatype);
1357                 
1358                 /* loop through ipo curves retrieved */
1359                 for (ale= act_data.first; ale; ale= ale->next) {
1360                         /* verify that this is indeed an ipo curve */
1361                         if (ale->key_data && ale->owner) {
1362                                 bActionChannel *achan= (bActionChannel *)ale->owner;
1363                                 IpoCurve *icu= (IpoCurve *)ale->key_data;
1364                                 
1365                                 if (ob)
1366                                         insertkey((ID *)ob, icu->blocktype, achan->name, NULL, icu->adrcode, 0);
1367                                 else
1368                                         insert_vert_icu(icu, cfra, icu->curval, 0);
1369                         }
1370                 }
1371                 
1372                 /* cleanup */
1373                 BLI_freelistN(&act_data);
1374         }
1375         else if (datatype == ACTCONT_SHAPEKEY) {
1376                 Key *key= (Key *)data;
1377                 IpoCurve *icu;
1378                 
1379                 /* ask user if they want to insert a keyframe */
1380                 mode = okee("Insert Keyframe?");
1381                 if (mode <= 0) return;
1382                 
1383                 if (key->ipo) {
1384                         for (icu= key->ipo->curve.first; icu; icu=icu->next) {
1385                                 insert_vert_icu(icu, cfra, icu->curval, 0);
1386                         }
1387                 }
1388         }
1389         
1390         BIF_undo_push("Insert Key");
1391         allspace(REMAKEIPO, 0);
1392         allqueue(REDRAWACTION, 0);
1393         allqueue(REDRAWIPO, 0);
1394         allqueue(REDRAWNLA, 0);
1395 }
1396
1397 /* delete selected keyframes */
1398 void delete_action_keys (void)
1399 {
1400         ListBase act_data = {NULL, NULL};
1401         bActListElem *ale;
1402         void *data;
1403         short datatype;
1404         int filter;
1405         
1406         /* determine what type of data we are operating on */
1407         data = get_action_context(&datatype);
1408         if (data == NULL) return;
1409         
1410         /* filter data */
1411         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
1412         actdata_filter(&act_data, filter, data, datatype);
1413         
1414         /* loop through filtered data and delete selected keys */
1415         for (ale= act_data.first; ale; ale= ale->next) {
1416                 delete_ipo_keys((Ipo *)ale->key_data);
1417         }
1418         
1419         /* free filtered list */
1420         BLI_freelistN(&act_data);
1421         
1422         if (datatype == ACTCONT_ACTION)
1423                 remake_action_ipos(data);
1424         
1425         BIF_undo_push("Delete Action Keys");
1426         allspace(REMAKEIPO, 0);
1427         allqueue(REDRAWACTION, 0);
1428         allqueue(REDRAWIPO, 0);
1429         allqueue(REDRAWNLA, 0);
1430 }
1431
1432 /* delete selected action-channels (only achans and conchans are considered) */
1433 void delete_action_channels (void)
1434 {
1435         ListBase act_data = {NULL, NULL};
1436         bActListElem *ale, *next;
1437         bAction *act;
1438         void *data;
1439         short datatype;
1440         int filter;
1441         
1442         /* determine what type of data we are operating on */
1443         data = get_action_context(&datatype);
1444         if (data == NULL) return;
1445         if (datatype != ACTCONT_ACTION) return;
1446         act= (bAction *)data;
1447         
1448         /* deal with groups first */
1449         if (act->groups.first) {
1450                 bActionGroup *agrp, *grp;
1451                 bActionChannel *chan, *nchan;
1452                 
1453                 /* unlink achan's that belonged to this group (and make sure they're not selected if they weren't visible) */
1454                 for (agrp= act->groups.first; agrp; agrp= grp) {
1455                         grp= agrp->next;
1456                         
1457                         /* remove if group is selected */
1458                         if (SEL_AGRP(agrp)) {
1459                                 for (chan= agrp->channels.first; chan && chan->grp==agrp; chan= nchan) {
1460                                         nchan= chan->next;
1461                                         
1462                                         action_groups_removeachan(act, chan);
1463                                         BLI_addtail(&act->chanbase, chan);
1464                                         
1465                                         if (EXPANDED_AGRP(agrp) == 0)
1466                                                 chan->flag &= ~(ACHAN_SELECTED|ACHAN_HILIGHTED);
1467                                 }
1468                                 
1469                                 BLI_freelinkN(&act->groups, agrp);
1470                         }
1471                 }
1472         }
1473         
1474         /* filter data */
1475         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_CHANNELS | ACTFILTER_SEL);
1476         actdata_filter(&act_data, filter, data, datatype);
1477         
1478         /* remove irrelevant entries */
1479         for (ale= act_data.first; ale; ale= next) {
1480                 next= ale->next;
1481                 
1482                 if (ale->type != ACTTYPE_ACHAN)
1483                         BLI_freelinkN(&act_data, ale);
1484         }
1485         
1486         /* clean up action channels */
1487         for (ale= act_data.first; ale; ale= next) {
1488                 bActionChannel *achan= (bActionChannel *)ale->data;
1489                 bConstraintChannel *conchan, *cnext;
1490                 next= ale->next;
1491                 
1492                 /* release reference to ipo users */
1493                 if (achan->ipo)
1494                         achan->ipo->id.us--;
1495                         
1496                 for (conchan= achan->constraintChannels.first; conchan; conchan=cnext) {
1497                         cnext= conchan->next;
1498                         
1499                         if (conchan->ipo)
1500                                 conchan->ipo->id.us--;
1501                 }
1502                 
1503                 /* free memory */
1504                 BLI_freelistN(&achan->constraintChannels);
1505                 BLI_freelinkN(&act->chanbase, achan);
1506                 BLI_freelinkN(&act_data, ale);
1507         }
1508                 
1509         remake_action_ipos(data);
1510         
1511         BIF_undo_push("Delete Action Channels");
1512         allspace(REMAKEIPO, 0);
1513         allqueue(REDRAWACTION, 0);
1514         allqueue(REDRAWIPO, 0);
1515         allqueue(REDRAWNLA, 0);
1516 }
1517
1518 /* 'Clean' IPO curves - remove any unnecessary keyframes */
1519 void clean_action (void)
1520 {       
1521         ListBase act_data = {NULL, NULL};
1522         bActListElem *ale;
1523         int filter;
1524         void *data;
1525         short datatype, ok;
1526         
1527         /* don't proceed any further if nothing to work on or user refuses */
1528         data= get_action_context(&datatype);
1529         ok= fbutton(&G.scene->toolsettings->clean_thresh, 
1530                                 0.0000001f, 1.0, 0.001, 0.1,
1531                                 "Clean Threshold");
1532         if (!ok) return;
1533         
1534         /* filter data */
1535         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_SEL | ACTFILTER_ONLYICU);
1536         actdata_filter(&act_data, filter, data, datatype);
1537         
1538         /* loop through filtered data and clean curves */
1539         for (ale= act_data.first; ale; ale= ale->next) {
1540                 clean_ipo_curve((IpoCurve *)ale->key_data);
1541         }
1542         
1543         /* admin and redraws */
1544         BLI_freelistN(&act_data);
1545         
1546         BIF_undo_push("Clean Action");
1547         allqueue(REMAKEIPO, 0);
1548         allqueue(REDRAWIPO, 0);
1549         allqueue(REDRAWACTION, 0);
1550         allqueue(REDRAWNLA, 0);
1551 }
1552
1553
1554 /* little cache for values... */
1555 typedef struct tempFrameValCache {
1556         float frame, val;
1557 } tempFrameValCache;
1558
1559 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
1560 void sample_action_keys (void)
1561 {       
1562         ListBase act_data = {NULL, NULL};
1563         bActListElem *ale;
1564         int filter;
1565         void *data;
1566         short datatype;
1567         
1568         /* sanity checks */
1569         data= get_action_context(&datatype);
1570         if (data == NULL) return;
1571         
1572         /* filter data */
1573         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_ONLYICU);
1574         actdata_filter(&act_data, filter, data, datatype);
1575         
1576         /* loop through filtered data and add keys between selected keyframes on every frame  */
1577         for (ale= act_data.first; ale; ale= ale->next) {
1578                 IpoCurve *icu= (IpoCurve *)ale->key_data;
1579                 BezTriple *bezt, *start=NULL, *end=NULL;
1580                 tempFrameValCache *value_cache, *fp;
1581                 int sfra, range;
1582                 int i, n;
1583                 
1584                 /* find selected keyframes... once pair has been found, add keyframes  */
1585                 for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
1586                         /* check if selected, and which end this is */
1587                         if (BEZSELECTED(bezt)) {
1588                                 if (start) {
1589                                         /* set end */
1590                                         end= bezt;
1591                                         
1592                                         /* cache values then add keyframes using these values, as adding
1593                                          * keyframes while sampling will affect the outcome...
1594                                          */
1595                                         range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) );
1596                                         sfra= (int)( floor(start->vec[1][0]) );
1597                                         
1598                                         if (range) {
1599                                                 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache");
1600                                                 
1601                                                 /*      sample values   */
1602                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
1603                                                         fp->frame= (float)(sfra + n);
1604                                                         fp->val= eval_icu(icu, fp->frame);
1605                                                 }
1606                                                 
1607                                                 /*      add keyframes with these        */
1608                                                 for (n=0, fp=value_cache; n<range && fp; n++, fp++) {
1609                                                         insert_vert_icu(icu, fp->frame, fp->val, 1);
1610                                                 }
1611                                                 
1612                                                 /* free temp cache */
1613                                                 MEM_freeN(value_cache);
1614                                         }
1615                                         
1616                                         /* as we added keyframes, we need to compensate so that bezt is at the right place */
1617                                         bezt = icu->bezt + i + range - 1;
1618                                         i += (range - 1);
1619                                         
1620                                         /* bezt was selected, so it now marks the start of a whole new chain to search */
1621                                         start= bezt;
1622                                         end= NULL;
1623                                 }
1624                                 else {
1625                                         /* just set start keyframe */
1626                                         start= bezt;
1627                                         end= NULL;
1628                                 }
1629                         }
1630                 }
1631                 
1632                 /* recalculate channel's handles? */
1633                 calchandles_ipocurve(icu);
1634         }
1635         
1636         /* admin and redraws */
1637         BLI_freelistN(&act_data);
1638         
1639         BIF_undo_push("Sample Action Keys");
1640         allqueue(REMAKEIPO, 0);
1641         allqueue(REDRAWIPO, 0);
1642         allqueue(REDRAWACTION, 0);
1643         allqueue(REDRAWNLA, 0);
1644 }
1645
1646 /* **************************************************** */
1647 /* COPY/PASTE FOR ACTIONS */
1648 /* - The copy/paste buffer currently stores a set of Action Channels, with temporary
1649  *      IPO-blocks, and also temporary IpoCurves which only contain the selected keyframes.
1650  * - Only pastes between compatable data is possible (i.e. same achan->name, ipo-curve type, etc.)
1651  *      Unless there is only one element in the buffer, names are also tested to check for compatability.
1652  * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
1653  *      the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
1654  * - The earliest frame is calculated per copy operation.
1655  */
1656
1657 /* globals for copy/paste data (like for other copy/paste buffers) */
1658 ListBase actcopybuf = {NULL, NULL};
1659 static float actcopy_firstframe= 999999999.0f;
1660
1661 /* This function frees any MEM_calloc'ed copy/paste buffer data */
1662 void free_actcopybuf ()
1663 {
1664         bActionChannel *achan, *anext;
1665         bConstraintChannel *conchan, *cnext;
1666         
1667         for (achan= actcopybuf.first; achan; achan= anext) {
1668                 anext= achan->next;
1669                 
1670                 if (achan->ipo) {
1671                         free_ipo(achan->ipo);
1672                         MEM_freeN(achan->ipo);
1673                 }
1674                 
1675                 for (conchan=achan->constraintChannels.first; conchan; conchan=cnext) {
1676                         cnext= conchan->next;
1677                         
1678                         if (conchan->ipo) {
1679                                 free_ipo(conchan->ipo);
1680                                 MEM_freeN(conchan->ipo);
1681                         }
1682                         
1683                         BLI_freelinkN(&achan->constraintChannels, conchan);
1684                 }
1685                 
1686                 BLI_freelinkN(&actcopybuf, achan);
1687         }
1688         
1689         actcopybuf.first= actcopybuf.last= NULL;
1690         actcopy_firstframe= 999999999.0f;
1691 }
1692
1693 /* This function adds data to the copy/paste buffer, freeing existing data first
1694  * Only the selected action channels gets their selected keyframes copied.
1695  */
1696 void copy_actdata ()
1697 {
1698         ListBase act_data = {NULL, NULL};
1699         bActListElem *ale;
1700         int filter;
1701         void *data;
1702         short datatype;
1703         
1704         /* clear buffer first */
1705         free_actcopybuf();
1706         
1707         /* get data */
1708         data= get_action_context(&datatype);
1709         if (data == NULL) return;
1710         
1711         /* filter data */
1712         filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_IPOKEYS);
1713         actdata_filter(&act_data, filter, data, datatype);
1714         
1715         /* assume that each of these is an ipo-block */
1716         for (ale= act_data.first; ale; ale= ale->next) {
1717                 bActionChannel *achan;
1718                 Ipo *ipo= ale->key_data;
1719                 Ipo *ipn;
1720                 IpoCurve *icu, *icn;
1721                 BezTriple *bezt;
1722                 int i;
1723                 
1724                 /* coerce an action-channel out of owner */
1725                 if (ale->ownertype == ACTTYPE_ACHAN) {
1726                         bActionChannel *achanO= ale->owner;
1727                         achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
1728                         strcpy(achan->name, achanO->name);
1729                 }
1730                 else if (ale->ownertype == ACTTYPE_SHAPEKEY) {
1731                         achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
1732                         strcpy(achan->name, "#ACP_ShapeKey");
1733                 }
1734                 else
1735                         continue;
1736                 BLI_addtail(&actcopybuf, achan);
1737                 
1738                 /* add constraint channel if needed, then add new ipo-block */
1739                 if (ale->type == ACTTYPE_CONCHAN) {
1740                         bConstraintChannel *conchanO= ale->data;
1741                         bConstraintChannel *conchan;
1742                         
1743                         conchan= MEM_callocN(sizeof(bConstraintChannel), "ActCopyPasteConchan");
1744                         strcpy(conchan->name, conchanO->name);
1745                         BLI_addtail(&achan->constraintChannels, conchan);
1746                         
1747                         conchan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
1748                 }
1749                 else {
1750                         achan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
1751                 }
1752                 ipn->blocktype = ipo->blocktype;
1753                 
1754                 /* now loop through curves, and only copy selected keyframes */
1755                 for (icu= ipo->curve.first; icu; icu= icu->next) {
1756                         /* allocate a new curve */
1757                         icn= MEM_callocN(sizeof(IpoCurve), "ActCopyPasteIcu");
1758                         icn->blocktype = icu->blocktype;
1759                         icn->adrcode = icu->adrcode;
1760                         BLI_addtail(&ipn->curve, icn);
1761                         
1762                         /* find selected BezTriples to add to the buffer (and set first frame) */
1763                         for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
1764                                 if (BEZSELECTED(bezt)) {
1765                                         /* add to buffer ipo-curve */
1766                                         insert_bezt_icu(icn, bezt);
1767                                         
1768                                         /* check if this is the earliest frame encountered so far */
1769                                         if (bezt->vec[1][0] < actcopy_firstframe)
1770                                                 actcopy_firstframe= bezt->vec[1][0];
1771                                 }
1772                         }
1773                 }
1774         }
1775         
1776         /* check if anything ended up in the buffer */
1777         if (ELEM(NULL, actcopybuf.first, actcopybuf.last))
1778                 error("Nothing copied to buffer");
1779         
1780         /* free temp memory */
1781         BLI_freelistN(&act_data);
1782 }
1783
1784 void paste_actdata ()
1785 {
1786         ListBase act_data = {NULL, NULL};
1787         bActListElem *ale;
1788         int filter;
1789         void *data;
1790         short datatype;
1791         
1792         short no_name= 0;
1793         float offset = CFRA - actcopy_firstframe;
1794         
1795         /* check if buffer is empty */
1796         if (ELEM(NULL, actcopybuf.first, actcopybuf.last)) {
1797                 error("No data in buffer to paste");
1798                 return;
1799         }
1800         /* check if single channel in buffer (disregard names if so)  */
1801         if (actcopybuf.first == actcopybuf.last)
1802                 no_name= 1;
1803         
1804         /* get data */
1805         data= get_action_context(&datatype);
1806         if (data == NULL) return;
1807         
1808         /* filter data */
1809         filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
1810         actdata_filter(&act_data, filter, data, datatype);
1811         
1812         /* from selected channels */
1813         for (ale= act_data.first; ale; ale= ale->next) {
1814                 Ipo *ipo_src=NULL, *ipo_dst=ale->key_data;
1815                 bActionChannel *achan;
1816                 IpoCurve *ico, *icu;
1817                 BezTriple *bezt;
1818                 int i;
1819                 
1820                 /* find matching ipo-block */
1821                 for (achan= actcopybuf.first; achan; achan= achan->next) {
1822                         /* try to match data */
1823                         if (ale->ownertype == ACTTYPE_ACHAN) {
1824                                 bActionChannel *achant= ale->owner;
1825                                 
1826                                 /* check if we have a corresponding action channel */
1827                                 if ((no_name) || (strcmp(achan->name, achant->name)==0)) {
1828                                         /* check if this is a constraint channel */
1829                                         if (ale->type == ACTTYPE_CONCHAN) {
1830                                                 bConstraintChannel *conchant= ale->data;
1831                                                 bConstraintChannel *conchan;
1832                                                 
1833                                                 for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
1834                                                         if (strcmp(conchan->name, conchant->name)==0) {
1835                                                                 ipo_src= conchan->ipo;
1836                                                                 break;
1837                                                         }
1838                                                 }
1839                                                 if (ipo_src) break;
1840                                         }
1841                                         else {
1842                                                 ipo_src= achan->ipo;
1843                                                 break;
1844                                         }
1845                                 }
1846                         }
1847                         else if (ale->ownertype == ACTTYPE_SHAPEKEY) {
1848                                 /* check if this action channel is "#ACP_ShapeKey" */
1849                                 if ((no_name) || (strcmp(achan->name, "#ACP_ShapeKey")==0)) {
1850                                         ipo_src= achan->ipo;
1851                                         break;
1852                                 }
1853                         }       
1854                 }
1855                 
1856                 /* this shouldn't happen, but it might */
1857                 if (ELEM(NULL, ipo_src, ipo_dst))
1858                         continue;
1859                 
1860                 /* loop over curves, pasting keyframes */
1861                 for (icu= ipo_dst->curve.first; icu; icu= icu->next) {
1862                         for (ico= ipo_src->curve.first; ico; ico= ico->next) {
1863                                 /* only paste if compatable blocktype + adrcode */
1864                                 if ((ico->blocktype==icu->blocktype) && (ico->adrcode==icu->adrcode)) {
1865                                         /* just start pasting, with the the first keyframe on the current frame, and so on */
1866                                         for (i=0, bezt=ico->bezt; i < ico->totvert; i++, bezt++) {                                              
1867                                                 /* temporarily apply offset to src beztriple while copying */
1868                                                 bezt->vec[0][0] += offset;
1869                                                 bezt->vec[1][0] += offset;
1870                                                 bezt->vec[2][0] += offset;
1871                                                 
1872                                                 /* insert the keyframe */
1873                                                 insert_bezt_icu(icu, bezt);
1874                                                 
1875                                                 /* un-apply offset from src beztriple after copying */
1876                                                 bezt->vec[0][0] -= offset;
1877                                                 bezt->vec[1][0] -= offset;
1878                                                 bezt->vec[2][0] -= offset;
1879                                         }
1880                                         
1881                                         /* recalculate channel's handles? */
1882                                         calchandles_ipocurve(icu);
1883                                         
1884                                         /* done for this channel */
1885                                         break;
1886                                 }
1887                         }
1888                 }
1889         }
1890         
1891         /* free temp memory */
1892         BLI_freelistN(&act_data);
1893         
1894         /* undo and redraw stuff */
1895         allqueue(REDRAWVIEW3D, 0);
1896         allspace(REMAKEIPO, 0);
1897         allqueue(REDRAWACTION, 0);
1898         allqueue(REDRAWIPO, 0);
1899         allqueue(REDRAWNLA, 0);
1900         BIF_undo_push("Paste Action Keyframes");
1901 }
1902
1903 /* **************************************************** */
1904 /* VARIOUS SETTINGS */
1905
1906 /* This function combines several features related to setting 
1907  * various ipo extrapolation/interpolation
1908  */
1909 void action_set_ipo_flags (short mode, short event)
1910 {
1911         ListBase act_data = {NULL, NULL};
1912         bActListElem *ale;
1913         void *data;
1914         short datatype;
1915         int filter;
1916         
1917         /* determine what type of data we are operating on */
1918         data = get_action_context(&datatype);
1919         if (data == NULL) return;
1920         
1921         /* determine which set of processing we are doing */
1922         switch (mode) {
1923                 case SET_EXTEND_POPUP:
1924                 {
1925                         /* present popup menu for ipo extrapolation type */
1926                         event
1927                                 =  pupmenu("Channel Extending Type %t|"
1928                                                    "Constant %x11|"
1929                                                    "Extrapolation %x12|"
1930                                                    "Cyclic %x13|"
1931                                                    "Cyclic extrapolation %x14");
1932                         if (event < 1) return;
1933                 }
1934                         break;
1935                 case SET_IPO_POPUP:
1936                 {
1937                         /* present popup menu for ipo interpolation type */
1938                         event
1939                                 =  pupmenu("Channel Ipo Type %t|"
1940                                                    "Constant %x1|"
1941                                                    "Linear %x2|"
1942                                                    "Bezier %x3");
1943                         if (event < 1) return;
1944                 }
1945                         break;
1946                         
1947                 case SET_IPO_MENU:      /* called from menus */
1948                 case SET_EXTEND_MENU:
1949                         break;
1950                         
1951                 default: /* weird, unhandled case */
1952                         return;
1953         }
1954         
1955         /* filter data */
1956         filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
1957         actdata_filter(&act_data, filter, data, datatype);
1958         
1959         /* loop through setting flags */
1960         for (ale= act_data.first; ale; ale= ale->next) {
1961                 Ipo *ipo= (Ipo *)ale->key_data; 
1962         
1963                 /* depending on the mode */
1964                 switch (mode) {
1965                         case SET_EXTEND_POPUP: /* extrapolation */
1966                         case SET_EXTEND_MENU:
1967                         {
1968                                 switch (event) {
1969                                         case SET_EXTEND_CONSTANT:
1970                                                 setexprap_ipoloop(ipo, IPO_HORIZ);
1971                                                 break;
1972                                         case SET_EXTEND_EXTRAPOLATION:
1973                                                 setexprap_ipoloop(ipo, IPO_DIR);
1974                                                 break;
1975                                         case SET_EXTEND_CYCLIC:
1976                                                 setexprap_ipoloop(ipo, IPO_CYCL);
1977                                                 break;
1978                                         case SET_EXTEND_CYCLICEXTRAPOLATION:
1979                                                 setexprap_ipoloop(ipo, IPO_CYCLX);
1980                                                 break;
1981                                 }
1982                         }
1983                                 break;
1984                         case SET_IPO_POPUP: /* interpolation */
1985                         case SET_IPO_MENU:
1986                         {
1987                                 setipotype_ipo(ipo, event);
1988                         }
1989                                 break;
1990                 }
1991         }
1992         
1993         /* cleanup */
1994         BLI_freelistN(&act_data);
1995         
1996         if (datatype == ACTCONT_ACTION)
1997                 remake_action_ipos(data);
1998         
1999         BIF_undo_push("Set Ipo Type");
2000         allspace(REMAKEIPO, 0);
2001         allqueue(REDRAWACTION, 0);
2002         allqueue(REDRAWIPO, 0);
2003         allqueue(REDRAWNLA, 0);
2004 }
2005
2006 /* this function sets the handles on keyframes */
2007 void sethandles_action_keys (int code)
2008 {
2009         ListBase act_data = {NULL, NULL};
2010         bActListElem *ale;
2011         void *data;
2012         short datatype;
2013         int filter;
2014         
2015         /* determine what type of data we are operating on */
2016         data = get_action_context(&datatype);
2017         if (data == NULL) return;
2018         
2019         /* filter data */
2020         filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
2021         actdata_filter(&act_data, filter, data, datatype);
2022         
2023         /* loop through setting flags */
2024         for (ale= act_data.first; ale; ale= ale->next) {
2025                 sethandles_ipo_keys((Ipo *)ale->key_data, code);
2026         }
2027         
2028         /* cleanup */
2029         BLI_freelistN(&act_data);
2030         if (datatype == ACTCONT_ACTION)
2031                 remake_action_ipos(data);
2032         
2033         BIF_undo_push("Set Handle Type");
2034         allspace(REMAKEIPO, 0);
2035         allqueue(REDRAWACTION, 0);
2036         allqueue(REDRAWIPO, 0);
2037         allqueue(REDRAWNLA, 0);
2038 }
2039
2040 /* ----------------------------------------- */
2041
2042 /* this gets called when nkey is pressed (no Transform Properties panel yet) */
2043 static void numbuts_action ()
2044 {
2045         void *data;
2046         short datatype;
2047         
2048         void *act_channel;
2049         short chantype;
2050         
2051         bActionGroup *agrp= NULL;
2052         bActionChannel *achan= NULL;
2053         bConstraintChannel *conchan= NULL;
2054         IpoCurve *icu= NULL;
2055         KeyBlock *kb= NULL;
2056         
2057         short mval[2];
2058         
2059         int but=0;
2060     char str[64];
2061         short expand, protect, mute;
2062         float slidermin, slidermax;
2063         
2064         
2065         /* determine what type of data we are operating on */
2066         data = get_action_context(&datatype);
2067         if (data == NULL) return;
2068         
2069         /* figure out what is under cursor */
2070         getmouseco_areawin(mval);
2071         if (mval[0] > NAMEWIDTH) 
2072                 return;
2073         act_channel= get_nearest_act_channel(mval, &chantype);
2074         
2075         /* create items for clever-numbut */
2076         if (chantype == ACTTYPE_ACHAN) {
2077                 /* Action Channel */
2078                 achan= (bActionChannel *)act_channel;
2079                 
2080                 strcpy(str, achan->name);
2081                 protect= (achan->flag & ACHAN_PROTECTED);
2082                 expand = (achan->flag & ACHAN_EXPANDED);
2083                 mute = (achan->ipo)? (achan->ipo->muteipo): 0;
2084                 
2085                 add_numbut(but++, TEX, "ActChan: ", 0, 31, str, "Name of Action Channel");
2086                 add_numbut(but++, TOG|SHO, "Expanded", 0, 24, &expand, "Action Channel is Expanded");
2087                 add_numbut(but++, TOG|SHO, "Muted", 0, 24, &mute, "Channel is Muted");
2088                 add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Channel is Protected");
2089         }
2090         else if (chantype == ACTTYPE_CONCHAN) {
2091                 /* Constraint Channel */
2092                 conchan= (bConstraintChannel *)act_channel;
2093                 
2094                 strcpy(str, conchan->name);
2095                 protect= (conchan->flag & CONSTRAINT_CHANNEL_PROTECTED);
2096                 mute = (conchan->ipo)? (conchan->ipo->muteipo): 0;
2097                 
2098                 add_numbut(but++, TEX, "ConChan: ", 0, 29, str, "Name of Constraint Channel");
2099                 add_numbut(but++, TOG|SHO, "Muted", 0, 24, &mute, "Channel is Muted");
2100                 add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Channel is Protected");
2101         }
2102         else if (chantype == ACTTYPE_ICU) {
2103                 /* IPO Curve */
2104                 icu= (IpoCurve *)act_channel;
2105                 
2106                 if (G.saction->pin)
2107                         sprintf(str, getname_ipocurve(icu, NULL));
2108                 else
2109                         sprintf(str, getname_ipocurve(icu, OBACT));
2110                 
2111                 if (IS_EQ(icu->slide_max, icu->slide_min)) {
2112                         if (IS_EQ(icu->ymax, icu->ymin)) {
2113                                 icu->slide_min= -100.0;
2114                                 icu->slide_max= 100.0;
2115                         }
2116                         else {
2117                                 icu->slide_min= icu->ymin;
2118                                 icu->slide_max= icu->ymax;
2119                         }
2120                 }
2121                 slidermin= icu->slide_min;
2122                 slidermax= icu->slide_max;
2123                 
2124                 //protect= (icu->flag & IPO_PROTECT);
2125                 mute = (icu->flag & IPO_MUTE);
2126                 
2127                 add_numbut(but++, NUM|FLO, "Slider Min:", -10000, slidermax, &slidermin, 0);
2128                 add_numbut(but++, NUM|FLO, "Slider Max:", slidermin, 10000, &slidermax, 0);
2129                 add_numbut(but++, TOG|SHO, "Muted", 0, 24, &mute, "Channel is Muted");
2130                 //add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Channel is Protected");
2131         }
2132         else if (chantype == ACTTYPE_SHAPEKEY) {
2133                 /* Shape Key */
2134                 kb= (KeyBlock *)act_channel;
2135                 
2136                 if (kb->name[0] == '\0') {
2137                         Key *key= (Key *)data;
2138                         int keynum= BLI_findindex(&key->block, kb);
2139                         
2140                         sprintf(str, "Key %d", keynum);
2141                 }
2142                 else
2143                         strcpy(str, kb->name);
2144                 
2145                 if (kb->slidermin >= kb->slidermax) {
2146                         kb->slidermin = 0.0;
2147                         kb->slidermax = 1.0;
2148                 }
2149                 
2150             add_numbut(but++, TEX, "KB: ", 0, 24, str, 
2151                        "Does this really need a tool tip?");
2152                 add_numbut(but++, NUM|FLO, "Slider Min:", 
2153                                    -10000, kb->slidermax, &kb->slidermin, 0);
2154                 add_numbut(but++, NUM|FLO, "Slider Max:", 
2155                                    kb->slidermin, 10000, &kb->slidermax, 0);
2156         }
2157         else if (chantype == ACTTYPE_GROUP) {
2158                 /* Action Group */
2159                 agrp= (bActionGroup *)act_channel;
2160                 
2161                 strcpy(str, agrp->name);
2162                 protect= (agrp->flag & AGRP_PROTECTED);
2163                 expand = (agrp->flag & AGRP_EXPANDED);
2164                 
2165                 add_numbut(but++, TEX, "ActGroup: ", 0, 31, str, "Name of Action Group");
2166                 add_numbut(but++, TOG|SHO, "Expanded", 0, 24, &expand, "Action Group is Expanded");
2167                 add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Group is Protected");
2168         }
2169         else {
2170                 /* nothing under-cursor */
2171                 return;
2172         }
2173         
2174         /* draw clever-numbut */
2175     if (do_clever_numbuts(str, but, REDRAW)) {
2176                 /* restore settings based on type */
2177                 if (icu) {
2178                         icu->slide_min= slidermin;
2179                         icu->slide_max= slidermax;
2180                         
2181                         //if (protect) icu->flag |= IPO_PROTECT;
2182                         //else icu->flag &= ~IPO_PROTECT;
2183                         if (mute) icu->flag |= IPO_MUTE;
2184                         else icu->flag &= ~IPO_MUTE;
2185                 }
2186                 else if (conchan) {
2187                         strcpy(conchan->name, str);
2188                         
2189                         if (protect) conchan->flag |= CONSTRAINT_CHANNEL_PROTECTED;
2190                         else conchan->flag &= ~CONSTRAINT_CHANNEL_PROTECTED;
2191                         
2192                         if (conchan->ipo)
2193                                 conchan->ipo->muteipo = mute;
2194                 }
2195                 else if (achan) {
2196                         strcpy(achan->name, str);
2197                         
2198                         if (expand) achan->flag |= ACHAN_EXPANDED;
2199                         else achan->flag &= ~ACHAN_EXPANDED;
2200                         
2201                         if (protect) achan->flag |= ACHAN_PROTECTED;
2202                         else achan->flag &= ~ACHAN_PROTECTED;
2203                         
2204                         if (achan->ipo)
2205                                 achan->ipo->muteipo = mute;
2206                 }
2207                 else if (agrp) {
2208                         strcpy(agrp->name, str);
2209                         BLI_uniquename(&( ((bAction *)data)->groups ), agrp, "Group", offsetof(bActionGroup, name), 32);
2210                         
2211                         if (expand) agrp->flag |= AGRP_EXPANDED;
2212                         else agrp->flag &= ~AGRP_EXPANDED;
2213                         
2214                         if (protect) agrp->flag |= AGRP_PROTECTED;
2215                         else agrp->flag &= ~AGRP_PROTECTED;
2216                 }
2217                 
2218         allqueue(REDRAWACTION, 0);
2219                 allspace(REMAKEIPO, 0);
2220                 allqueue(REDRAWIPO, 0);
2221                 allqueue(REDRAWVIEW3D, 0);
2222         }
2223 }
2224
2225
2226
2227 /* **************************************************** */
2228 /* CHANNEL SELECTION */
2229
2230 /* select_mode = SELECT_REPLACE
2231  *             = SELECT_ADD
2232  *             = SELECT_SUBTRACT
2233  *             = SELECT_INVERT
2234  */
2235 static void select_action_group (bAction *act, bActionGroup *agrp, int selectmode) 
2236 {
2237         /* Select the channel based on the selection mode */
2238         short select;
2239
2240         switch (selectmode) {
2241         case SELECT_ADD:
2242                 agrp->flag |= AGRP_SELECTED;
2243                 break;
2244         case SELECT_SUBTRACT:
2245                 agrp->flag &= ~AGRP_SELECTED;
2246                 break;
2247         case SELECT_INVERT:
2248                 agrp->flag ^= AGRP_SELECTED;
2249                 break;
2250         }
2251         select = (agrp->flag & AGRP_SELECTED) ? 1 : 0;
2252
2253         set_active_actiongroup(act, agrp, select);
2254 }
2255
2256 static void hilight_channel(bAction *act, bActionChannel *achan, short select)
2257 {
2258         bActionChannel *curchan;
2259
2260         if (!act)
2261                 return;
2262
2263         for (curchan=act->chanbase.first; curchan; curchan=curchan->next) {
2264                 if (curchan==achan && select)
2265                         curchan->flag |= ACHAN_HILIGHTED;
2266                 else
2267                         curchan->flag &= ~ACHAN_HILIGHTED;
2268         }
2269 }
2270
2271 /* messy call... */
2272 static void select_poseelement_by_name(char *name, int select)
2273 {
2274         /* Syncs selection of channels with selection of object elements in posemode */
2275         Object *ob= OBACT;
2276         bPoseChannel *pchan;
2277         
2278         if (!ob || ob->type!=OB_ARMATURE)
2279                 return;
2280         
2281         if(select==2) {
2282                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
2283                         pchan->bone->flag &= ~(BONE_ACTIVE);
2284         }
2285         
2286         pchan= get_pose_channel(ob->pose, name);
2287         if(pchan) {
2288                 if(select)
2289                         pchan->bone->flag |= (BONE_SELECTED);
2290                 else 
2291                         pchan->bone->flag &= ~(BONE_SELECTED);
2292                 if(select==2)
2293                         pchan->bone->flag |= (BONE_ACTIVE);
2294         }
2295 }
2296
2297 /* apparently within active object context */
2298 /* called extern, like on bone selection */
2299 void select_actionchannel_by_name (bAction *act, char *name, int select)
2300 {
2301         bActionChannel *achan;
2302
2303         if (!act)
2304                 return;
2305
2306         for (achan = act->chanbase.first; achan; achan= achan->next) {
2307                 if (!strcmp(achan->name, name)) {
2308                         if (select) {
2309                                 achan->flag |= ACHAN_SELECTED;
2310                                 hilight_channel(act, achan, 1);
2311                         }
2312                         else {
2313                                 achan->flag &= ~ACHAN_SELECTED;
2314                                 hilight_channel(act, achan, 0);
2315                         }
2316                         return;
2317                 }
2318         }
2319 }
2320
2321 /* select_mode = SELECT_REPLACE
2322  *             = SELECT_ADD
2323  *             = SELECT_SUBTRACT
2324  *             = SELECT_INVERT
2325  */
2326
2327 /* exported for outliner (ton) */
2328 /* apparently within active object context */
2329 int select_channel(bAction *act, bActionChannel *achan, int selectmode) 
2330 {
2331         /* Select the channel based on the selection mode */
2332         int flag;
2333
2334         switch (selectmode) {
2335         case SELECT_ADD:
2336                 achan->flag |= ACHAN_SELECTED;
2337                 break;
2338         case SELECT_SUBTRACT:
2339                 achan->flag &= ~ACHAN_SELECTED;
2340                 break;
2341         case SELECT_INVERT:
2342                 achan->flag ^= ACHAN_SELECTED;
2343                 break;
2344         }
2345         flag = (achan->flag & ACHAN_SELECTED) ? 1 : 0;
2346
2347         hilight_channel(act, achan, flag);
2348         select_poseelement_by_name(achan->name, flag);
2349
2350         return flag;
2351 }
2352
2353 static int select_constraint_channel(bAction *act, 
2354                                      bConstraintChannel *conchan, 
2355                                      int selectmode) 
2356 {
2357         /* Select the constraint channel based on the selection mode */
2358         int flag;
2359
2360         switch (selectmode) {
2361         case SELECT_ADD:
2362                 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
2363                 break;
2364         case SELECT_SUBTRACT:
2365                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
2366                 break;
2367         case SELECT_INVERT:
2368                 conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
2369                 break;
2370         }
2371         flag = (conchan->flag & CONSTRAINT_CHANNEL_SELECT) ? 1 : 0;
2372
2373         return flag;
2374 }
2375
2376 int select_icu_channel(bAction *act, IpoCurve *icu, int selectmode) 
2377 {
2378         /* Select the channel based on the selection mode */
2379         int flag;
2380
2381         switch (selectmode) {
2382         case SELECT_ADD:
2383                 icu->flag |= IPO_SELECT;
2384                 break;
2385         case SELECT_SUBTRACT:
2386                 icu->flag &= ~IPO_SELECT;
2387                 break;
2388         case SELECT_INVERT:
2389                 icu->flag ^= IPO_SELECT;
2390                 break;
2391         }
2392         flag = (icu->flag & IPO_SELECT) ? 1 : 0;
2393         return flag;
2394 }
2395
2396 /* ----------------------------------------- */
2397
2398 /* deselects action channels in given action */
2399 void deselect_actionchannels (bAction *act, short test)
2400 {
2401         ListBase act_data = {NULL, NULL};
2402         bActListElem *ale;
2403         int filter, sel=1;
2404         
2405         /* filter data */
2406         filter= ACTFILTER_VISIBLE;
2407         actdata_filter(&act_data, filter, act, ACTCONT_ACTION);
2408         
2409         /* See if we should be selecting or deselecting */
2410         if (test) {
2411                 for (ale= act_data.first; ale; ale= ale->next) {
2412                         if (sel == 0) 
2413                                 break;
2414                         
2415                         switch (ale->type) {
2416                                 case ACTTYPE_GROUP:
2417                                         if (ale->flag & AGRP_SELECTED)
2418                                                 sel= 0;
2419                                         break;
2420                                 case ACTTYPE_ACHAN:
2421                                         if (ale->flag & ACHAN_SELECTED) 
2422                                                 sel= 0;
2423                                         break;
2424                                 case ACTTYPE_CONCHAN:
2425                                         if (ale->flag & CONSTRAINT_CHANNEL_SELECT) 
2426                                                 sel=0;
2427                                         break;
2428                                 case ACTTYPE_ICU:
2429                                         if (ale->flag & IPO_SELECT)
2430                                                 sel=0;
2431                                         break;
2432                         }
2433                 }
2434         }
2435         else
2436                 sel= 0;
2437                 
2438         /* Now set the flags */
2439         for (ale= act_data.first; ale; ale= ale->next) {
2440                 switch (ale->type) {
2441                         case ACTTYPE_GROUP:
2442                         {
2443                                 bActionGroup *agrp= (bActionGroup *)ale->data;
2444                                 
2445                                 if (sel)
2446                                         agrp->flag |= AGRP_SELECTED;
2447                                 else
2448                                         agrp->flag &= ~AGRP_SELECTED;
2449                         }
2450                                 break;
2451                         case ACTTYPE_ACHAN:
2452                         {
2453                                 bActionChannel *achan= (bActionChannel *)ale->data;
2454                                 
2455                                 if (sel)
2456                                         achan->flag |= ACHAN_SELECTED;
2457                                 else
2458                                         achan->flag &= ~ACHAN_SELECTED;
2459                                 select_poseelement_by_name(achan->name, sel);
2460                         }
2461                                 break;
2462                         case ACTTYPE_CONCHAN:
2463                         {
2464                                 bConstraintChannel *conchan= (bConstraintChannel *)ale->data;
2465                                 
2466                                 if (sel)
2467                                         conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
2468                                 else
2469                                         conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
2470                         }
2471                                 break;
2472                         case ACTTYPE_ICU:
2473                         {
2474                                 IpoCurve *icu= (IpoCurve *)ale->data;
2475                                 
2476                                 if (sel)
2477                                         icu->flag |= IPO_SELECT;
2478                                 else
2479                                         icu->flag &= ~IPO_SELECT;
2480                         }
2481                                 break;
2482                 }
2483         }
2484         
2485         /* Cleanup */
2486         BLI_freelistN(&act_data);
2487 }
2488
2489 /* deselects channels in the action editor */
2490 void deselect_action_channels (short test)
2491 {
2492         void *data;
2493         short datatype;
2494         
2495         /* determine what type of data we are operating on */
2496         data = get_action_context(&datatype);
2497         if (data == NULL) return;
2498         
2499         /* based on type */
2500         if (datatype == ACTCONT_ACTION)
2501                 deselect_actionchannels(data, test);
2502         // should shapekey channels be allowed to do this? 
2503 }
2504
2505 /* deselects keyframes in the action editor */
2506 void deselect_action_keys (short test, short sel)
2507 {
2508         ListBase act_data = {NULL, NULL};
2509         bActListElem *ale;
2510         int filter;
2511         void *data;
2512         short datatype;
2513         
2514         /* determine what type of data we are operating on */
2515         data = get_action_context(&datatype);
2516         if (data == NULL) return;
2517                 
2518         /* filter data */
2519         filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
2520         actdata_filter(&act_data, filter, data, datatype);
2521         
2522         /* See if we should be selecting or deselecting */
2523         if (test) {
2524                 for (ale= act_data.first; ale; ale= ale->next) {
2525                         if (is_ipo_key_selected(ale->key_data)) {
2526                                 sel= 0;
2527                                 break;
2528                         }
2529                 }
2530         }
2531                 
2532         /* Now set the flags */
2533         for (ale= act_data.first; ale; ale= ale->next) {
2534                 set_ipo_key_selection(ale->key_data, sel);
2535         }
2536         
2537         /* Cleanup */
2538         BLI_freelistN(&act_data);
2539 }
2540
2541 /* selects all keyframes in the action editor - per channel or time 
2542  *      mode = 0: all in channel; mode = 1: all in frame
2543  */
2544 void selectall_action_keys (short mval[], short mode, short select_mode)
2545 {
2546         void *data;
2547         short datatype;
2548         
2549         /* determine what type of data we are operating on */
2550         data = get_action_context(&datatype);
2551         if (data == NULL) return;
2552                 
2553         if (select_mode == SELECT_REPLACE) {
2554                 deselect_action_keys(0, 0);
2555                 select_mode = SELECT_ADD;
2556         }
2557                 
2558         /* depending on mode */
2559         switch (mode) {
2560                 case 0: /* all in channel*/
2561                 {
2562                         void *act_channel;
2563                         short chantype;
2564                         
2565                         /* get channel, and act according to type */
2566                         act_channel= get_nearest_act_channel(mval, &chantype);
2567                         switch (chantype) {
2568                                 case ACTTYPE_GROUP:     
2569                                 {
2570                                         bActionGroup *agrp= (bActionGroup *)act_channel;
2571                                         bActionChannel *achan;
2572                                         bConstraintChannel *conchan;
2573                                         
2574                                         for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
2575                                                 select_ipo_bezier_keys(achan->ipo, select_mode);
2576                                                 
2577                                                 for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) 
2578                                                         select_ipo_bezier_keys(conchan->ipo, select_mode);
2579                                         }
2580                                 }
2581                                         break;
2582                                 case ACTTYPE_ACHAN:
2583                                 {
2584                                         bActionChannel *achan= (bActionChannel *)act_channel;
2585                                         select_ipo_bezier_keys(achan->ipo, select_mode);
2586                                 }
2587                                         break;
2588                                 case ACTTYPE_CONCHAN:
2589                                 {
2590                                         bConstraintChannel *conchan= (bConstraintChannel *)act_channel;
2591                                         select_ipo_bezier_keys(conchan->ipo, select_mode);
2592                                 }
2593                                         break;
2594                                 case ACTTYPE_ICU:
2595                                 {
2596                                         IpoCurve *icu= (IpoCurve *)act_channel;
2597                                         select_icu_bezier_keys(icu, select_mode);
2598                                 }
2599                                         break;
2600                         }
2601                 }
2602                         break;
2603                 case 1: /* all in frame */
2604                 {
2605                         ListBase act_data = {NULL, NULL};
2606                         bActListElem *ale;
2607                         int filter;
2608                         rcti rect;
2609                         rctf rectf;
2610                         
2611                         /* use bounding box to find kframe */
2612                         rect.xmin = rect.xmax = mval[0];
2613                         rect.ymin = rect.ymax = mval[1];
2614                         
2615                         mval[0]= rect.xmin;
2616                         mval[1]= rect.ymin+2;
2617                         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
2618                         rectf.xmax= rectf.xmin;
2619                         rectf.ymax= rectf.ymin;
2620                         
2621                         rectf.xmin = rectf.xmin - 0.5;
2622                         rectf.xmax = rectf.xmax + 0.5;
2623                         
2624                         /* filter data */
2625                         filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
2626                         actdata_filter(&act_data, filter, data, datatype);
2627                                 
2628                         /* Now set the flags */
2629                         for (ale= act_data.first; ale; ale= ale->next)
2630                                 borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, select_mode);
2631                         
2632                         /* Cleanup */
2633                         BLI_freelistN(&act_data);
2634                 }
2635                 break;
2636         }
2637         
2638         allqueue(REDRAWNLA, 0);
2639         allqueue(REDRAWACTION, 0);
2640         allqueue(REDRAWIPO, 0);
2641 }
2642
2643 /* Selects all visible keyframes between the specified markers */
2644 void markers_selectkeys_between (void)
2645 {
2646         ListBase act_data = {NULL, NULL};
2647         bActListElem *ale;
2648         int filter;
2649         void *data;
2650         short datatype;
2651         float min, max;
2652         
2653         /* determine what type of data we are operating on */
2654         data = get_action_context(&datatype);
2655         if (data == NULL) return;
2656         
2657         /* get extreme markers */
2658         get_minmax_markers(1, &min, &max);
2659         if (min==max) return;
2660         min -= 0.5f;
2661         max += 0.5f;
2662         
2663         /* filter data */
2664         filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
2665         actdata_filter(&act_data, filter, data, datatype);
2666                 
2667         /* select keys in-between */
2668         for (ale= act_data.first; ale; ale= ale->next) {
2669                 if(NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
2670                         actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1);
2671                         borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
2672                         actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
2673                 }
2674                 else {
2675                         borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
2676                 }
2677         }
2678         
2679         /* Cleanup */
2680         BLI_freelistN(&act_data);
2681 }
2682
2683 /* Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */
2684 void selectkeys_leftright (short leftright, short select_mode)
2685 {
2686         ListBase act_data = {NULL, NULL};
2687         bActListElem *ale;
2688         int filter;
2689         void *data;
2690         short datatype;
2691         float min, max;
2692         
2693         if (select_mode==SELECT_REPLACE) {
2694                 select_mode=SELECT_ADD;
2695                 deselect_action_keys(0, 0);
2696         }
2697         
2698         /* determine what type of data we are operating on */
2699         data = get_action_context(&datatype);
2700         if (data == NULL) return;
2701         
2702         if (leftright == 1) {
2703                 min = -MAXFRAMEF;
2704                 max = (float)(CFRA + 0.1f);
2705         } 
2706         else {
2707                 min = (float)(CFRA - 0.1f);
2708                 max = MAXFRAMEF;
2709         }
2710         
2711         /* filter data */
2712         filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
2713         actdata_filter(&act_data, filter, data, datatype);
2714                 
2715         /* select keys on the side where most data occurs */
2716         for (ale= act_data.first; ale; ale= ale->next) {
2717                 if(NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
2718                         actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1);
2719                         borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
2720                         actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
2721                 }
2722                 else {
2723                         borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
2724                 }
2725         }
2726         
2727         /* Cleanup */
2728         BLI_freelistN(&act_data);
2729         
2730         allqueue(REDRAWNLA, 0);
2731         allqueue(REDRAWACTION, 0);
2732         allqueue(REDRAWIPO, 0);
2733 }
2734
2735 /* ----------------------------------------- */
2736
2737 /* Jumps to the frame where the next/previous keyframe (that is visible) occurs 
2738  *      dir: indicates direction
2739  */
2740 void nextprev_action_keyframe (short dir)
2741 {
2742         ListBase act_data = {NULL, NULL};
2743         bActListElem *ale;
2744         int filter;
2745         void *data;
2746         short datatype;
2747         
2748         ListBase elems= {NULL, NULL};
2749         CfraElem *ce, *nearest=NULL;
2750         float dist, min_dist= 1000000;
2751         
2752         
2753         /* determine what type of data we are operating on */
2754         data = get_action_context(&datatype);
2755         if (data == NULL) return;
2756         
2757         /* abort if no direction */
2758         if (dir == 0)
2759                 return;
2760         
2761         /* get list of keyframes that can be used (in global-time) */
2762         filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
2763         actdata_filter(&act_data, filter, data, datatype);
2764         
2765         for (ale= act_data.first; ale; ale= ale->next) {
2766                 if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
2767                         actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1); 
2768                         make_cfra_list(ale->key_data, &elems);
2769                         actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
2770                 }
2771                 else 
2772                         make_cfra_list(ale->key_data, &elems);
2773         }
2774         
2775         BLI_freelistN(&act_data);
2776         
2777         /* find nearest keyframe to current frame */
2778         for (ce= elems.first; ce; ce= ce->next) {
2779                 dist= ABS(ce->cfra - CFRA);
2780                 
2781                 if (dist < min_dist) {
2782                         min_dist= dist;
2783                         nearest= ce;
2784                 }
2785         }
2786         
2787         /* if a nearest keyframe was found, use the one either side */
2788         if (nearest) {
2789                 short changed= 0;
2790                 
2791                 if ((dir > 0) && (nearest->next)) {
2792                         CFRA= nearest->next->cfra;
2793                         changed= 1;
2794                 }
2795                 else if ((dir < 0) && (nearest->prev)) {
2796                         CFRA= nearest->prev->cfra;
2797                         changed= 1;
2798                 }
2799                         
2800                 if (changed) {  
2801                         update_for_newframe();  
2802                         allqueue(REDRAWALL, 0);
2803                 }
2804         }
2805         
2806         /* free temp data */
2807         BLI_freelistN(&elems);
2808 }
2809
2810 /* ----------------------------------------- */
2811
2812 /* This function makes a list of the selected keyframes
2813  * in the ipo curves it has been passed
2814  */
2815 static void make_sel_cfra_list (Ipo *ipo, ListBase *elems)
2816 {
2817         IpoCurve *icu;
2818         
2819         if (ipo == NULL) return;
2820         
2821         for (icu= ipo->curve.first; icu; icu= icu->next) {
2822                 BezTriple *bezt;
2823                 int a= 0;
2824                 
2825                 for (bezt=icu->bezt; a<icu->totvert; a++, bezt++) {
2826                         if (bezt && BEZSELECTED(bezt))
2827                                 add_to_cfra_elem(elems, bezt);
2828                 }
2829         }
2830 }
2831
2832 /* This function selects all key frames in the same column(s) as a already selected key(s)
2833  * or marker(s), or all the keyframes on a particular frame (triggered by a RMB on x-scrollbar)
2834  */
2835 void column_select_action_keys (int mode)
2836 {
2837         ListBase elems= {NULL, NULL};
2838         CfraElem *ce;
2839         IpoCurve *icu;
2840         ListBase act_data = {NULL, NULL};
2841         bActListElem *ale;
2842         int filter;
2843         void *data;
2844         short datatype;
2845         
2846         /* determine what type of data we are operating on */
2847         data = get_action_context(&datatype);
2848         if (data == NULL) return;
2849         
2850         /* build list of columns */
2851         switch (mode) {
2852                 case 1: /* list of selected keys */
2853                         filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
2854                         actdata_filter(&act_data, filter, data, datatype);
2855                         
2856                         for (ale= act_data.first; ale; ale= ale->next)
2857                                 make_sel_cfra_list(ale->key_data, &elems);
2858                         
2859                         BLI_freelistN(&act_data);
2860                         break;
2861                 case 2: /* list of selected markers */
2862                         make_marker_cfra_list(&elems, 1);
2863                         
2864                         /* apply scaled action correction if needed */
2865                         if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
2866                                 for (ce= elems.first; ce; ce= ce->next) 
2867                                         ce->cfra= get_action_frame(OBACT, ce->cfra);
2868                         }
2869                         break;
2870         }
2871         
2872         /* loop through all of the keys and select additional keyframes
2873          * based on the keys found to be selected above
2874          */
2875         filter= (ACTFILTER_VISIBLE | ACTFILTER_ONLYICU);
2876         actdata_filter(&act_data, filter, data, datatype);
2877         
2878         for (ale= act_data.first; ale; ale= ale->next) {
2879                 for (ce= elems.first; ce; ce= ce->next) {
2880                         for (icu= ale->key_data; icu; icu= icu->next) {
2881                                 BezTriple *bezt;
2882                                 int verts = 0;
2883                                 
2884                                 for (bezt=icu->bezt; verts<icu->totvert; bezt++, verts++) {
2885                                         if (bezt) {
2886                                                 if( (int)(ce->cfra) == (int)(bezt->vec[1][0]) )
2887                                                         bezt->f2 |= 1;
2888                                         }
2889                                 }
2890                         }
2891                 }
2892         }
2893         
2894         BLI_freelistN(&act_data);
2895         BLI_freelistN(&elems);
2896 }
2897
2898
2899 /* some quick defines for borderselect modes */
2900 enum {
2901         ACTEDIT_BORDERSEL_ALL = 0,
2902         ACTEDIT_BORDERSEL_FRA,
2903         ACTEDIT_BORDERSEL_CHA
2904 };
2905
2906 /* borderselect: for keyframes only */
2907 void borderselect_action (void)
2908 {
2909         ListBase act_data = {NULL, NULL};
2910         bActListElem *ale;
2911         int filter;
2912         void *data;
2913         short datatype;
2914         
2915         rcti rect;
2916         rctf rectf;
2917         int val, selectmode, mode;
2918         int (*select_function)(BezTriple *);
2919         short mval[2];
2920         float ymin, ymax;
2921         
2922         /* determine what type of data we are operating on */
2923         data = get_action_context(&datatype);
2924         if (data == NULL) return;
2925         
2926         /* what should be selected (based on the starting location of cursor) */
2927         getmouseco_areawin(mval);
2928         if (IN_2D_VERT_SCROLL(mval)) 
2929                 mode = ACTEDIT_BORDERSEL_CHA;
2930         else if (IN_2D_HORIZ_SCROLL(mval))
2931                 mode = ACTEDIT_BORDERSEL_FRA;
2932         else
2933                 mode = ACTEDIT_BORDERSEL_ALL;
2934         
2935         /* draw and handle the borderselect stuff (ui) and get the select rect */
2936         if ( (val = get_border(&rect, 3)) ) {
2937                 if (val == LEFTMOUSE) {
2938                         selectmode = SELECT_ADD;
2939                         select_function = select_bezier_add;
2940                 }
2941                 else {
2942                         selectmode = SELECT_SUBTRACT;
2943                         select_function = select_bezier_subtract;
2944                 }
2945                 
2946                 mval[0]= rect.xmin;
2947                 mval[1]= rect.ymin+2;
2948                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
2949                 mval[0]= rect.xmax;
2950                 mval[1]= rect.ymax-2;
2951                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
2952                 
2953                 /* if action is mapped in NLA, it returns a correction */
2954                 if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
2955                         rectf.xmin= get_action_frame(OBACT, rectf.xmin);
2956                         rectf.xmax= get_action_frame(OBACT, rectf.xmax);
2957                 }
2958                 
2959                 ymax = CHANNELHEIGHT/2;
2960                 
2961                 /* filter data */
2962                 filter= (ACTFILTER_VISIBLE | ACTFILTER_CHANNELS);
2963                 actdata_filter(&act_data, filter, data, datatype);
2964                 
2965                 /* loop over data, doing border select */
2966                 for (ale= act_data.first; ale; ale= ale->next) {
2967                         ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
2968                         
2969                         /* what gets selected depends on the mode (based on initial position of cursor) */
2970                         switch (mode) {
2971                         case ACTEDIT_BORDERSEL_FRA: /* all in frame(s) */
2972                                 if (ale->key_data) {
2973                                         if (ale->datatype == ALE_IPO)
2974                                                 borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, selectmode);
2975                                         else if (ale->datatype == ALE_ICU)
2976                                                 borderselect_icu_key(ale->key_data, rectf.xmin, rectf.xmax, select_function);
2977                                 }
2978                                 else if (ale->type == ACTTYPE_GROUP) {
2979                                         bActionGroup *agrp= ale->data;
2980                                         bActionChannel *achan;
2981                                         bConstraintChannel *conchan;
2982                                         
2983                                         for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
2984                                                 borderselect_ipo_key(achan->ipo, rectf.xmin, rectf.xmax, selectmode);
2985                                                 
2986                                                 for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
2987                                                         borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
2988                                         }
2989                                 }
2990                                 break;
2991                         case ACTEDIT_BORDERSEL_CHA: /* all in channel(s) */
2992                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
2993                                         if (ale->key_data) {
2994                                                 if (ale->datatype == ALE_IPO)
2995                                                         select_ipo_bezier_keys(ale->key_data, selectmode);
2996                                                 else if (ale->datatype == ALE_ICU)
2997                                                         select_icu_bezier_keys(ale->key_data, selectmode);
2998                                         }
2999                                         else if (ale->type == ACTTYPE_GROUP) {
3000                                                 bActionGroup *agrp= ale->data;
3001                                                 bActionChannel *achan;
3002                                                 bConstraintChannel *conchan;
3003                                                 
3004                                                 for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
3005                                                         select_ipo_bezier_keys(achan->ipo, selectmode);
3006                                                         
3007                                                         for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
3008                                                                 select_ipo_bezier_keys(conchan->ipo, selectmode);
3009                                                 }
3010                                         }
3011                                 }
3012                                 break;
3013                         default: /* any keyframe inside region defined by region */
3014                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
3015                                         if (ale->key_data) {
3016                                                 if (ale->datatype == ALE_IPO)
3017                                                         borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, selectmode);
3018                                                 else if (ale->datatype == ALE_ICU)
3019                                                         borderselect_icu_key(ale->key_data, rectf.xmin, rectf.xmax, select_function);
3020                                         }
3021                                         else if (ale->type == ACTTYPE_GROUP) {
3022                                                 bActionGroup *agrp= ale->data;
3023                                                 bActionChannel *achan;
3024                                                 bConstraintChannel *conchan;
3025                                                 
3026                                                 for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
3027                                                         borderselect_ipo_key(achan->ipo, rectf.xmin, rectf.xmax, selectmode);
3028                                                         
3029                                                         for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
3030                                                                 borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, selectmode);
3031                                                 }
3032                                         }
3033                                 }
3034                         }
3035                         
3036                         ymax=ymin;
3037                 }
3038                 
3039                 /* cleanup */
3040                 BLI_freelistN(&act_data);
3041                 
3042                 BIF_undo_push("Border Select Action");
3043                 allqueue(REDRAWIPO, 0);
3044                 allqueue(REDRAWACTION, 0);
3045                 allqueue(REDRAWNLA, 0);
3046         }
3047 }
3048
3049 /* **************************************************** */
3050 /* MOUSE-HANDLING */
3051
3052 /* right-hand side - mouse click */
3053 static void mouse_action (int selectmode)
3054 {
3055         void *data;
3056         short datatype;
3057         
3058         bAction *act= NULL;
3059         bActionGroup *agrp= NULL;
3060         bActionChannel *achan= NULL;
3061         bConstraintChannel *conchan= NULL;
3062         IpoCurve *icu= NULL;
3063         TimeMarker *marker, *pmarker;
3064         
3065         void *act_channel;
3066         short sel, act_type;
3067         float selx;
3068         
3069         /* determine what type of data we are operating on */
3070         data = get_action_context(&datatype);
3071         if (data == NULL) return;
3072         if (datatype == ACTCONT_ACTION) act= (bAction *)data;
3073
3074         act_channel= get_nearest_action_key(&selx, &sel, &act_type, &achan);
3075         marker= find_nearest_marker(SCE_MARKERS, 1);
3076         pmarker= (act) ? find_nearest_marker(&act->markers, 1) : NULL;
3077         
3078         if (marker) {
3079                 /* what about scene's markers? */               
3080                 if (selectmode == SELECT_REPLACE) {                     
3081                         deselect_markers(0, 0);
3082                         marker->flag |= SELECT;
3083                 }
3084                 else if (selectmode == SELECT_INVERT) {
3085                         if (marker->flag & SELECT)
3086                                 marker->flag &= ~SELECT;
3087                         else
3088                                 marker->flag |= SELECT;
3089                 }
3090                 else if (selectmode == SELECT_ADD) 
3091                         marker->flag |= SELECT;
3092                 else if (selectmode == SELECT_SUBTRACT)
3093                         marker->flag &= ~SELECT;
3094                &nb