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