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