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