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