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