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