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