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