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