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