- another huge commit! read this!
[blender.git] / source / blender / src / editaction.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <string.h>
34 #include <math.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #ifdef WIN32
41 #include "BLI_winstuff.h"
42 #endif
43
44 #include "MEM_guardedalloc.h"
45
46 #include "PIL_time.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
50
51 #include "DNA_action_types.h"
52 #include "DNA_armature_types.h"
53 #include "DNA_curve_types.h"
54 #include "DNA_ipo_types.h"
55 #include "DNA_object_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_screen_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_constraint_types.h"
60 #include "DNA_key_types.h"
61 #include "DNA_mesh_types.h"
62 #include "DNA_lattice_types.h"
63
64 #include "BKE_armature.h"
65 #include "BKE_constraint.h"
66 #include "BKE_displist.h"
67 #include "BKE_curve.h"
68 #include "BKE_ipo.h"
69 #include "BKE_global.h"
70 #include "BKE_library.h"
71 #include "BKE_main.h"
72 #include "BKE_action.h"
73 #include "BKE_key.h"
74
75 #include "BIF_gl.h"
76 #include "BIF_mywindow.h"
77 #include "BIF_toolbox.h"
78 #include "BIF_screen.h"
79 #include "BIF_space.h"
80 #include "BIF_butspace.h"
81 #include "BIF_interface.h"
82 #include "BIF_editview.h"
83 #include "BIF_poseobject.h"
84 #include "BIF_editarmature.h"
85
86 #include "BSE_edit.h"
87 #include "BSE_drawipo.h"
88 #include "BSE_headerbuttons.h"
89 #include "BSE_editipo.h"
90 #include "BSE_editaction.h"
91 #include "BSE_trans_types.h"
92 #include "BSE_editaction_types.h"
93
94 #include "BDR_editobject.h"
95
96 #include "interface.h"
97 #include "mydevice.h"
98 #include "blendef.h"
99 #include "nla.h"
100
101 static bPose    *g_posebuf=NULL;
102 extern int count_action_levels (bAction *act);
103
104 #define BEZSELECTED(bezt)   (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1))
105
106 /* Local Function prototypes */
107
108 static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float time);
109 static void flip_name (char *name);
110 static void mouse_actionchannels(bAction *act, short *mval, 
111                                  short *mvalo, int selectmode);
112 static void borderselect_action(void);
113 static void mouse_action(int selectmode);
114 static void mouse_mesh_action(int selectmode, Key *key);
115 static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **conchan);
116 static void sethandles_actionchannel_keys(int code);
117 static void delete_actionchannels(void);
118 static void delete_actionchannel_keys(void);
119 static void duplicate_actionchannel_keys(void);
120 static void transform_actionchannel_keys(char mode);
121 static void transform_meshchannel_keys(char mode, Key *key);
122 static void select_poseelement_by_name (char *name, int select);
123 static void hilight_channel (bAction *act, bActionChannel *chan, short hilight);
124 static void set_action_key_time (bAction *act, bPoseChannel *chan, int adrcode, short makecurve, float time);
125 /* Implementation */
126
127 short showsliders = 0;
128 short ACTWIDTH = NAMEWIDTH;
129
130 static void select_poseelement_by_name (char *name, int select)
131 {
132         /* Synchs selection of channels with selection of object elements in posemode */
133
134         Object *ob;
135
136         ob = G.obpose;
137         if (!ob)
138                 return;
139
140         switch (ob->type){
141         case OB_ARMATURE:
142                 select_bone_by_name ((bArmature*)ob->data, name, select);
143                 break;
144         default:
145                 break;
146         }
147 }
148 #ifdef __NLA_BAKE
149 bAction* bake_action_with_client (bAction *act, Object *armob, float tolerance)
150 {
151         bAction                 *result=NULL;
152         bActionChannel *achan;
153         float                   actlen;
154         int                             curframe;
155         char                    newname[64];
156         bArmature               *arm;
157         Bone                    *bone;
158         float                   oldframe;
159         bAction                 *temp;
160         bPoseChannel *pchan;
161
162         if (!act)
163                 return NULL;
164
165         arm = get_armature(armob);
166
167         
168         if (G.obedit){
169                 error ("Not in editmode");
170                 return NULL;
171         }
172
173         if (!arm){
174                 error ("Must have an armature selected");
175                 return NULL;
176         }
177         /* Get a new action */
178         result = add_empty_action();
179
180         /* Assign the new action a unique name */
181         sprintf (newname, "%s.BAKED", act->id.name+2);
182         rename_id(&result->id, newname);
183
184         actlen = calc_action_end(act);
185
186         oldframe = G.scene->r.cfra;
187
188         temp = armob->action;
189         armob->action = act;
190         
191         for (curframe=1; curframe<ceil(actlen+1); curframe++){
192
193                 /* Apply the old action */
194                 
195                 G.scene->r.cfra = curframe;
196
197                 /* Apply the object ipo */
198                 get_pose_from_action(&armob->pose, act, curframe);
199                 apply_pose_armature(arm, armob->pose, 1);
200                 clear_object_constraint_status(armob);
201                 where_is_armature_time(armob, curframe);
202                 
203                 /* For each channel: set avail keys with current values */
204                 for (pchan=armob->pose->chanbase.first; pchan; pchan=pchan->next){      
205
206                         /* Copy the constraints from the armature (if any) */
207
208                         bone = get_named_bone(arm, pchan->name);
209                         if (bone){
210
211                                 Mat4ToQuat(pchan->obmat, pchan->quat);
212                                 Mat4ToSize(pchan->obmat, pchan->size);
213                                 VECCOPY(pchan->loc, pchan->obmat[3]);
214                         
215                                 /* Apply to keys */      
216                                 set_action_key_time (result, pchan, AC_QUAT_X, 1, curframe);
217                                 set_action_key_time (result, pchan, AC_QUAT_Y, 1, curframe);
218                                 set_action_key_time (result, pchan, AC_QUAT_Z, 1, curframe);
219                                 set_action_key_time (result, pchan, AC_QUAT_W, 1, curframe);
220                                 set_action_key_time (result, pchan, AC_LOC_X, 1, curframe);
221                                 set_action_key_time (result, pchan, AC_LOC_Y, 1, curframe);
222                                 set_action_key_time (result, pchan, AC_LOC_Z, 1, curframe);
223                         }
224                 }
225         }
226
227         /* Make another pass to ensure all keyframes are set to linear interpolation mode */
228         for (achan = result->chanbase.first; achan; achan=achan->next){
229                 IpoCurve* icu;
230                 for (icu = achan->ipo->curve.first; icu; icu=icu->next){
231                         icu->ipo= IPO_LIN;
232                 }
233         }
234
235         notice ("Made new action \"%s\"", newname);
236         G.scene->r.cfra = oldframe;
237         armob->action = temp;
238         return result;
239 }
240 #endif
241
242 void select_actionchannel_by_name (bAction *act, char *name, int select)
243 {
244         bActionChannel *chan;
245
246         if (!act)
247                 return;
248
249         for (chan = act->chanbase.first; chan; chan=chan->next){
250                 if (!strcmp (chan->name, name)){
251                         act->achan = chan;
252                         if (select){
253                                 chan->flag |= ACHAN_SELECTED;
254                                 hilight_channel (act, chan, 1);
255                         }
256                         else{
257                                 chan->flag &= ~ACHAN_SELECTED;
258                                 hilight_channel (act, chan, 0);
259                         }
260                         return;
261                 }
262         }
263 }
264
265 void remake_action_ipos(bAction *act)
266 {
267         bActionChannel *chan;
268         bConstraintChannel *conchan;
269         IpoCurve                *icu;
270
271         for (chan= act->chanbase.first; chan; chan=chan->next){
272                 if (chan->ipo){
273                         for (icu = chan->ipo->curve.first; icu; icu=icu->next){
274                                 sort_time_ipocurve(icu);
275                                 testhandles_ipocurve(icu);
276                         }
277                 }
278                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
279                         if (conchan->ipo){
280                                 for (icu = conchan->ipo->curve.first; icu; icu=icu->next){
281                                         sort_time_ipocurve(icu);
282                                         testhandles_ipocurve(icu);
283                                 }
284                         }
285                 }
286         }
287 }
288
289 void remake_meshaction_ipos(Ipo *ipo)
290 {
291         /* this puts the bezier triples in proper
292          * order and makes sure the bezier handles
293          * aren't too strange.
294          */
295         IpoCurve *icu;
296
297         for (icu = ipo->curve.first; icu; icu=icu->next){
298                 sort_time_ipocurve(icu);
299                 testhandles_ipocurve(icu);
300         }
301 }
302
303 static void meshkey_do_redraw(Key *key)
304 {
305         remake_meshaction_ipos(key->ipo);
306     do_all_ipos();
307     do_spec_key(key);
308
309         allspace(REMAKEIPO, 0);
310         allqueue(REDRAWACTION, 0);
311         allqueue(REDRAWIPO, 0);
312         allqueue(REDRAWNLA, 0);
313
314 }
315
316 static void duplicate_meshchannel_keys(Key *key)
317 {
318         duplicate_ipo_keys(key->ipo);
319         transform_meshchannel_keys ('g', key);
320 }
321
322
323 static void duplicate_actionchannel_keys(void)
324 {
325         bAction *act;
326         bActionChannel *chan;
327         bConstraintChannel *conchan;
328
329         act=G.saction->action;
330         if (!act)
331                 return;
332
333         /* Find selected items */
334         for (chan = act->chanbase.first; chan; chan=chan->next){
335                 duplicate_ipo_keys(chan->ipo);
336                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
337                         duplicate_ipo_keys(conchan->ipo);
338         }
339
340         transform_actionchannel_keys ('g');
341 }
342
343 static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **rchan){
344         bAction *act;
345         bActionChannel *chan;
346         IpoCurve *icu;
347         bActionChannel *firstchan=NULL;
348         bConstraintChannel *conchan, *firstconchan=NULL;
349         int     foundsel=0;
350         float firstvert=-1, foundx=-1;
351                 int i;
352         short mval[2];
353         float ymin, ymax;
354         rctf    rectf;
355         *index=0;
356
357         *rchan=NULL;
358         act=G.saction->action; /* We presume that we are only called during a valid action */
359         
360         getmouseco_areawin (mval);
361
362         mval[0]-=7;
363         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
364
365         mval[0]+=14;
366         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
367
368         ymax = count_action_levels (act) * (CHANNELHEIGHT + CHANNELSKIP);
369
370         *sel=0;
371
372         for (chan=act->chanbase.first; chan; chan=chan->next){
373
374                 /* Check action channel */
375                 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
376                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
377                         for (icu=chan->ipo->curve.first; icu; icu=icu->next){
378                                 for (i=0; i<icu->totvert; i++){
379                                         if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
380                                                 if (!firstchan){
381                                                         firstchan=chan;
382                                                         firstvert=icu->bezt[i].vec[1][0];
383                                                         *sel = icu->bezt[i].f2 & 1;     
384                                                 }
385                                                 
386                                                 if (icu->bezt[i].f2 & 1){ 
387                                                         if (!foundsel){
388                                                                 foundsel=1;
389                                                                 foundx = icu->bezt[i].vec[1][0];
390                                                         }
391                                                 }
392                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
393                                                         *index=icu->bezt[i].vec[1][0];
394                                                         *sel = 0;
395                                                         return chan;
396                                                 }
397                                         }
398                                 }
399                         }
400                 }
401                 ymax=ymin;
402                 
403                 /* Check constraint channels */
404                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
405                         ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
406                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
407                                 for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
408                                         for (i=0; i<icu->totvert; i++){
409                                                 if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
410                                                         if (!firstchan){
411                                                                 firstchan=chan;
412                                                                 firstconchan=conchan;
413                                                                 firstvert=icu->bezt[i].vec[1][0];
414                                                                 *sel = icu->bezt[i].f2 & 1;     
415                                                         }
416                                                         
417                                                         if (icu->bezt[i].f2 & 1){ 
418                                                                 if (!foundsel){
419                                                                         foundsel=1;
420                                                                         foundx = icu->bezt[i].vec[1][0];
421                                                                 }
422                                                         }
423                                                         else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
424                                                                 *index=icu->bezt[i].vec[1][0];
425                                                                 *sel = 0;
426                                                                 *rchan = conchan;
427                                                                 return chan;
428                                                         }
429                                                 }
430                                         }
431                                 }
432                         }
433                         ymax=ymin;
434                 }
435         }       
436         
437         *rchan = firstconchan;
438         *index=firstvert;
439         return firstchan;
440 }
441
442 static IpoCurve *get_nearest_meshchannel_key (float *index, short *sel)
443 {
444         /* This function tries to find the RVK key that is
445          * closest to the user's mouse click
446          */
447     Key      *key;
448     IpoCurve *icu; 
449     IpoCurve *firsticu=NULL;
450     int      foundsel=0;
451     float    firstvert=-1, foundx=-1;
452         int      i;
453     short    mval[2];
454     float    ymin, ymax, ybase;
455     rctf     rectf;
456
457     *index=0;
458
459     key = get_action_mesh_key();
460         
461     /* lets get the mouse position and process it so 
462      * we can start testing selections
463      */
464     getmouseco_areawin (mval);
465     mval[0]-=7;
466     areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
467     mval[0]+=14;
468     areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
469
470     ybase = key->totkey * (CHANNELHEIGHT + CHANNELSKIP);
471     *sel=0;
472
473     /* lets loop through the IpoCurves trying to find the closest
474      * bezier
475      */
476     for (icu = key->ipo->curve.first; icu ; icu = icu->next) {
477         /* lets not deal with the "speed" Ipo
478          */
479         if (!icu->adrcode) continue;
480
481         ymax = ybase    - (CHANNELHEIGHT+CHANNELSKIP)*(icu->adrcode-1);
482         ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
483
484         /* Does this curve coorespond to the right
485          * strip?
486          */
487         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
488                         
489             /* loop through the beziers in the curve
490              */
491             for (i=0; i<icu->totvert; i++){
492
493                 /* Is this bezier in the right area?
494                  */
495                 if (icu->bezt[i].vec[1][0] > rectf.xmin && 
496                     icu->bezt[i].vec[1][0] <= rectf.xmax ){
497
498                     /* if no other curves have been picked ...
499                      */
500                     if (!firsticu){
501                         /* mark this curve/bezier as the first
502                          * selected
503                          */
504                         firsticu=icu;
505                         firstvert=icu->bezt[i].vec[1][0];
506
507                         /* sel = (is the bezier is already selected) ? 1 : 0;
508                          */
509                         *sel = icu->bezt[i].f2 & 1;     
510                     }
511
512                     /* if the bezier is selected ...
513                      */
514                     if (icu->bezt[i].f2 & 1){ 
515                         /* if we haven't found a selected one yet ...
516                          */
517                         if (!foundsel){
518                             /* record the found x value
519                              */
520                             foundsel=1;
521                             foundx = icu->bezt[i].vec[1][0];
522                         }
523                     }
524
525                     /* if the bezier is unselected and not at the x
526                      * position of a previous found selected bezier ...
527                      */
528                     else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
529                         /* lets return this found curve/bezier
530                          */
531                         *index=icu->bezt[i].vec[1][0];
532                         *sel = 0;
533                         return icu;
534                     }
535                 }
536             }
537         }
538         }
539         
540     /* return what we've found
541      */
542     *index=firstvert;
543     return firsticu;
544 }
545
546 static void mouse_action(int selectmode)
547 {
548         bAction *act;
549         short sel;
550         float   selx;
551         bActionChannel *chan;
552         bConstraintChannel *conchan;
553         short   mval[2];
554
555         act=G.saction->action;
556         if (!act)
557                 return;
558
559         getmouseco_areawin (mval);
560
561         chan=get_nearest_actionchannel_key(&selx, &sel, &conchan);
562
563         if (chan){
564                 if (selectmode == SELECT_REPLACE) {
565                         if (sel == 0)
566                                 selectmode = SELECT_ADD;
567                         else
568                                 selectmode = SELECT_SUBTRACT;
569                         deselect_actionchannel_keys(act, 0);
570                         deselect_actionchannels(act, 0);
571                         act->achan = chan;
572                         chan->flag |= ACHAN_SELECTED;
573                         hilight_channel (act, chan, 1);
574                 }
575                 
576                 if (conchan)
577                         select_ipo_key(conchan->ipo, selx, selectmode);
578                 else
579                         select_ipo_key(chan->ipo, selx, selectmode);
580
581                 allqueue(REDRAWIPO, 0);
582                 allqueue(REDRAWVIEW3D, 0);
583                 allqueue(REDRAWACTION, 0);
584                 allqueue(REDRAWNLA, 0);
585
586         }
587 }
588
589 static void mouse_mesh_action(int selectmode, Key *key)
590 {
591         /* Handle a right mouse click selection in an
592          * action window displaying RVK data
593          */
594
595     IpoCurve *icu;
596     short  sel;
597     float  selx;
598     short  mval[2];
599
600     /* going to assume that the only reason 
601      * we got here is because it has been 
602      * determined that we are a mesh with
603      * the right properties (i.e., have key
604      * data, etc)
605      */
606
607         /* get the click location, and the cooresponding
608          * ipo curve and selection time value
609          */
610     getmouseco_areawin (mval);
611     icu = get_nearest_meshchannel_key(&selx, &sel);
612
613     if (icu){
614         if (selectmode == SELECT_REPLACE) {
615                         /* if we had planned to replace the
616                          * selection, then we will first deselect
617                          * all of the keys, and if the clicked on
618                          * key had been unselected, we will select 
619                          * it, otherwise, we are done.
620                          */
621             deselect_meshchannel_keys(key, 0);
622
623             if (sel == 0)
624                 selectmode = SELECT_ADD;
625             else
626                                 /* the key is selected so we should
627                                  * deselect -- but everything is now deselected
628                                  * so we are done.
629                                  */
630                                 return;
631         }
632                 
633                 /* select the key using the given mode
634                  * and redraw as mush stuff as needed.
635                  */
636                 select_icu_key(icu, selx, selectmode);
637
638         allqueue(REDRAWIPO, 0);
639         allqueue(REDRAWVIEW3D, 0);
640         allqueue(REDRAWACTION, 0);
641         allqueue(REDRAWNLA, 0);
642
643     }
644 }
645
646 static void borderselect_action(void)
647
648         rcti rect;
649         rctf rectf;
650         int val, selectmode;            
651         short   mval[2];
652         bActionChannel *chan;
653         bConstraintChannel *conchan;
654         bAction *act;
655         float   ymin, ymax;
656
657         act=G.saction->action;
658
659
660         if (!act)
661                 return;
662
663         if ( (val = get_border(&rect, 3)) ){
664     if (val == LEFTMOUSE)
665       selectmode = SELECT_ADD;
666     else
667       selectmode = SELECT_SUBTRACT;
668
669                 mval[0]= rect.xmin;
670                 mval[1]= rect.ymin+2;
671                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
672                 mval[0]= rect.xmax;
673                 mval[1]= rect.ymax-2;
674                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
675                 
676                 ymax=count_action_levels(act) * (CHANNELHEIGHT+CHANNELSKIP);
677                 for (chan=act->chanbase.first; chan; chan=chan->next){
678                         
679                         /* Check action */
680                         ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
681                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
682           borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax,
683                                selectmode);
684
685                         ymax=ymin;
686
687                         /* Check constraints */
688                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
689                                 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
690                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
691                                         borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
692                                selectmode);
693                                 
694                                 ymax=ymin;
695                         }
696                 }       
697                 allqueue(REDRAWNLA, 0);
698                 allqueue(REDRAWACTION, 0);
699                 allqueue(REDRAWIPO, 0);
700         }
701 }
702
703 static void borderselect_mesh(Key *key)
704
705         rcti     rect;
706         int      val, adrcodemax, adrcodemin;
707         short    mval[2];
708         float    xmin, xmax;
709         int      (*select_function)(BezTriple *);
710         IpoCurve *icu;
711
712         if ( (val = get_border(&rect, 3)) ){
713                 /* set the selection function based on what
714                  * mouse button had been used in the border
715                  * select
716                  */
717                 if (val == LEFTMOUSE)
718                         select_function = select_bezier_add;
719                 else
720                         select_function = select_bezier_subtract;
721
722                 /* get the minimum and maximum adrcode numbers
723                  * for the IpoCurves (this is the number that
724                  * relates an IpoCurve to the keyblock it
725                  * controls).
726                  */
727                 mval[0]= rect.xmin;
728                 mval[1]= rect.ymin+2;
729                 adrcodemax = get_nearest_key_num(key, mval, &xmin);
730                 adrcodemax = (adrcodemax >= key->totkey) ? key->totkey : adrcodemax;
731
732                 mval[0]= rect.xmax;
733                 mval[1]= rect.ymax-2;
734                 adrcodemin = get_nearest_key_num(key, mval, &xmax);
735                 adrcodemin = (adrcodemin < 1) ? 1 : adrcodemin;
736
737                 /* Lets loop throug the IpoCurves and do borderselect
738                  * on the curves with adrcodes in our selected range.
739                  */
740                 for (icu = key->ipo->curve.first; icu ; icu = icu->next) {
741                         /* lets not deal with the "speed" Ipo
742                          */
743                         if (!icu->adrcode) continue;
744                         if ( (icu->adrcode >= adrcodemin) && 
745                                  (icu->adrcode <= adrcodemax) ) {
746                                 borderselect_icu_key(icu, xmin, xmax, select_function);
747                         }
748                 }
749
750                 /* redraw stuff */
751                 allqueue(REDRAWNLA, 0);
752                 allqueue(REDRAWACTION, 0);
753                 allqueue(REDRAWIPO, 0);
754         }
755 }
756
757
758 bActionChannel* get_hilighted_action_channel(bAction* action)
759 {
760         bActionChannel *chan;
761
762         if (!action)
763                 return NULL;
764
765         for (chan=action->chanbase.first; chan; chan=chan->next){
766                 if (chan->flag & ACHAN_SELECTED && chan->flag & ACHAN_HILIGHTED)
767                         return chan;
768         }
769
770         return NULL;
771
772 }
773
774 void set_exprap_action(int mode)
775 {
776         if(G.saction->action && G.saction->action->id.lib) return;
777
778         error ("Not yet implemented!");
779 }
780
781 void free_posebuf(void) 
782 {
783         if (g_posebuf){
784                 clear_pose(g_posebuf);
785                 MEM_freeN (g_posebuf);
786         }
787         g_posebuf=NULL;
788 }
789
790 void copy_posebuf (void)
791 {
792         Object *ob;
793
794         free_posebuf();
795
796         ob=G.obpose;
797         if (!ob){
798                 error ("Copybuf is empty");
799                 return;
800         }
801
802         filter_pose_keys();
803         copy_pose(&g_posebuf, ob->pose, 0);
804
805 }
806
807 static void flip_name (char *name)
808 {
809
810         char    prefix[128]={""};       /* The part before the facing */
811         char    suffix[128]={""};       /* The part after the facing */
812         char    replace[128]={""};      /* The replacement string */
813
814         char    *index=NULL;
815         /* Find the last period */
816
817         strcpy (prefix, name);
818
819         /* Check for an instance of .Right */
820         if (!index){
821                 index = strstr (prefix, "Right");
822                 if (index){
823                         *index=0;
824                         strcpy (replace, "Left");
825                         strcpy (suffix, index+6);
826                 }
827         }
828
829         /* Che ck for an instance of .RIGHT */
830         if (!index){
831                 index = strstr (prefix, "RIGHT");
832                 if (index){
833                         *index=0;
834                         strcpy (replace, "LEFT");
835                         strcpy (suffix, index+6);
836                 }
837         }
838
839
840         /* Check for an instance of .right */
841         if (!index){
842                 index = strstr (prefix, "right");
843                 if (index){
844                         *index=0;
845                         strcpy (replace, "left");
846                         strcpy (suffix, index+6);
847                 }
848         }
849
850         /* Check for an instance of .left */
851         if (!index){
852                 index = strstr (prefix, "left");
853                 if (index){
854                         *index=0;
855                         strcpy (replace, "right");
856                         strcpy (suffix, index+5);
857                 }
858         }
859
860         /* Check for an instance of .LEFT */
861         if (!index){
862                 index = strstr (prefix, "LEFT");
863                 if (index){
864                         *index=0;
865                         strcpy (replace, "RIGHT");
866                         strcpy (suffix, index+5);
867                 }
868         }
869
870         /* Check for an instance of .Left */
871         if (!index){
872                 index = strstr (prefix, "Left");
873                 if (index){
874                         *index=0;
875                         strcpy (replace, "Right");
876                         strcpy (suffix, index+5);
877                 }
878         }
879
880         /* check for an instance of .L */
881         if (!index){
882                 index = strstr (prefix, ".L");
883                 if (index){
884                         *index=0;
885                         strcpy (replace, ".R");
886                         strcpy (suffix, index+2);
887                 }
888         }
889
890         /* check for an instance of .l */
891         if (!index){
892                 index = strstr (prefix, ".l");
893                 if (index){
894                         *index=0;
895                         strcpy (replace, ".r");
896                         strcpy (suffix, index+2);
897                 }
898         }
899
900         /* Checl for an instance of .R */
901         if (!index){
902                 index = strstr (prefix, ".R");
903                 if (index){
904                         *index=0;
905                         strcpy (replace, ".L");
906                         strcpy (suffix, index+2);
907                 }
908         }
909
910         /* Checl for an instance of .r */
911         if (!index){
912                 index = strstr (prefix, ".r");
913                 if (index){
914                         *index=0;
915                         strcpy (replace, ".l");
916                         strcpy (suffix, index+2);
917                 }
918         }
919
920         sprintf (name, "%s%s%s", prefix, replace, suffix);
921 }
922
923 void paste_posebuf (int flip){
924         Object *ob;
925         bPoseChannel *temp, *chan;
926         float eul[4];
927         Base    *base;
928         int             newchan = 0;
929
930         ob=G.obpose;
931         if (!ob)
932                 return;
933
934         if (!g_posebuf){
935                 error ("Copybuf is empty");
936                 return;
937         };
938         
939         collect_pose_garbage(ob);
940
941         /* Safely merge all of the channels in this pose into
942         any existing pose */
943         if (ob->pose){
944                 if (U.uiflag & KEYINSERTACT){
945                         /* Display "Avail, all" dialog */
946                 }
947                 for (chan=g_posebuf->chanbase.first; chan; chan=chan->next){
948                         if (chan->flag & POSE_KEY){
949                                 temp = copy_pose_channel (chan);
950                                 if (flip){
951                                         flip_name (temp->name);
952                                         temp->loc[0]*=-1;
953
954                                         QuatToEul(temp->quat, eul);
955                                         eul[1]*=-1;
956                                         eul[2]*=-1;
957                                         EulToQuat(eul, temp->quat);
958                                 }
959
960                                 temp = set_pose_channel (ob->pose, temp);
961
962                                 if (U.uiflag & KEYINSERTACT){
963                                         /* Set keys on pose */
964                                         if (chan->flag & POSE_ROT){
965                                                 set_action_key(ob->action, temp, AC_QUAT_X, newchan);
966                                                 set_action_key(ob->action, temp, AC_QUAT_Y, newchan);
967                                                 set_action_key(ob->action, temp, AC_QUAT_Z, newchan);
968                                                 set_action_key(ob->action, temp, AC_QUAT_W, newchan);
969                                         };
970                                         if (chan->flag & POSE_SIZE){
971                                                 set_action_key(ob->action, temp, AC_SIZE_X, newchan);
972                                                 set_action_key(ob->action, temp, AC_SIZE_Y, newchan);
973                                                 set_action_key(ob->action, temp, AC_SIZE_Z, newchan);
974                                         };
975                                         if (chan->flag & POSE_LOC){
976                                                 set_action_key(ob->action, temp, AC_LOC_X, newchan);
977                                                 set_action_key(ob->action, temp, AC_LOC_Y, newchan);
978                                                 set_action_key(ob->action, temp, AC_LOC_Z, newchan);
979                                         };                                      
980                                 }
981                         }
982                 }
983
984                 if (U.uiflag & KEYINSERTACT){
985                         remake_action_ipos(ob->action);
986                         allqueue (REDRAWIPO, 0);
987                         allqueue (REDRAWVIEW3D, 0);
988                         allqueue (REDRAWACTION, 0);             
989                         allqueue(REDRAWNLA, 0);
990                 }
991
992                 /* Update deformation children */
993                 if (G.obpose->type == OB_ARMATURE){
994                         for (base= FIRSTBASE; base; base= base->next){
995                                 if (G.obpose==base->object->parent){
996                                         if (base->object->partype==PARSKEL)
997                                                 makeDispList(base->object);
998                                 }
999                         }
1000                 }
1001         }
1002 }
1003
1004 void set_action_key (struct bAction *act, struct bPoseChannel *chan, int adrcode, short makecurve)
1005 {
1006         set_action_key_time (act, chan, adrcode, makecurve, frame_to_float(CFRA));
1007 }
1008
1009 static void set_action_key_time (bAction *act, bPoseChannel *chan, int adrcode, short makecurve, float time)
1010 {
1011         bActionChannel  *achan;
1012         char    ipstr[256];
1013
1014         if (!act)
1015                 return;
1016
1017         if (!chan)
1018                 return;
1019         /* See if this action channel exists already */ 
1020         for (achan=act->chanbase.first; achan; achan=achan->next){
1021                 if (!strcmp (chan->name, achan->name))
1022                         break;
1023         }
1024
1025         if (!achan){
1026                 if (!makecurve)
1027                         return;
1028                 achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
1029                 strcpy (achan->name, chan->name);
1030                 BLI_addtail (&act->chanbase, achan);
1031         }
1032
1033         /* Ensure the channel appears selected in the action window */
1034         /* ton: added flag hilighted, for display in ipowin. dunno what the difference is between select/hilite */
1035         achan->flag |= ACHAN_SELECTED|ACHAN_HILIGHTED;
1036
1037         /* Ensure this action channel has a valid Ipo */
1038         if (!achan->ipo){
1039                 sprintf (ipstr, "%s.%s", act->id.name+2, chan->name);
1040                 ipstr[23]=0;
1041                 achan->ipo=     add_ipo(ipstr, ID_AC);  
1042         }
1043
1044         insertactionkey(act, achan, chan, adrcode, makecurve, time);
1045
1046 }
1047
1048 static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float cfra)
1049 {
1050         IpoCurve *icu;
1051         void *poin;
1052         float curval;
1053         int type;
1054         ID *id;
1055         
1056         if (!act){
1057                 return;
1058         }
1059         if (act->id.lib){
1060                 error ("Can't pose libactions");
1061                 return;
1062         }
1063         act->achan=achan;
1064         act->pchan=chan;
1065
1066         id=(ID*) act;
1067
1068         /* First see if this curve exists */
1069         if (!makecurve){
1070                 if (!achan->ipo)
1071                         return;
1072
1073                 for (icu = achan->ipo->curve.first; icu; icu=icu->next){
1074                         if (icu->adrcode == adrcode)
1075                                 break;
1076                 }
1077                 if (!icu)
1078                         return;
1079         }
1080
1081         
1082         icu = get_ipocurve (id, GS(id->name), adrcode, achan->ipo);
1083
1084         if(icu) {
1085                 poin= get_ipo_poin(id, icu, &type);
1086                 if(poin) {
1087                         curval= read_ipo_poin(poin, type);
1088         //              cfra= frame_to_float(CFRA);
1089                         insert_vert_ipo(icu, cfra, curval);
1090                 }
1091         }
1092         
1093 }
1094
1095 bAction *add_empty_action(void)
1096 {
1097         bAction *act;
1098
1099         act= alloc_libblock(&G.main->action, ID_AC, "Action");
1100         act->id.flag |= LIB_FAKEUSER;
1101         act->id.us++;
1102         return act;
1103 }
1104
1105 static void transform_actionchannel_keys(char mode)
1106 {
1107         bAction *act;
1108         TransVert *tv;
1109         int /*sel=0,*/  i;
1110         bActionChannel  *chan;
1111         short   mvals[2], mvalc[2], cent[2];
1112         float   sval[2], cval[2], lastcval[2];
1113         short   cancel=0;
1114         float   fac=0.0F;
1115         int             loop=1;
1116         int             tvtot=0;
1117         float   deltax, startx;
1118         float   cenf[2];
1119         int             invert=0, firsttime=1;
1120         char    str[256];
1121         bConstraintChannel *conchan;
1122
1123         act=G.saction->action;
1124
1125         /* Ensure that partial selections result in beztriple selections */
1126         for (chan=act->chanbase.first; chan; chan=chan->next){
1127                 tvtot+=fullselect_ipo_keys(chan->ipo);
1128
1129                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1130                         tvtot+=fullselect_ipo_keys(conchan->ipo);
1131         }
1132         
1133         /* If nothing is selected, bail out */
1134         if (!tvtot)
1135                 return;
1136         
1137         
1138         /* Build the transvert structure */
1139         tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
1140         tvtot=0;
1141         for (chan=act->chanbase.first; chan; chan=chan->next){
1142                 /* Add the actionchannel */
1143                 tvtot = add_trans_ipo_keys(chan->ipo, tv, tvtot);
1144                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1145                         tvtot = add_trans_ipo_keys(conchan->ipo, tv, tvtot);
1146         }
1147
1148         /* Do the event loop */
1149         cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2;
1150         cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2;
1151         areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]);
1152
1153         getmouseco_areawin (mvals);
1154         areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
1155
1156         startx=sval[0];
1157         while (loop) {
1158                 /*              Get the input */
1159                 /*              If we're cancelling, reset transformations */
1160                 /*                      Else calc new transformation */
1161                 /*              Perform the transformations */
1162                 while (qtest()) {
1163                         short val;
1164                         unsigned short event= extern_qread(&val);
1165
1166                         if (val) {
1167                                 switch (event) {
1168                                 case LEFTMOUSE:
1169                                 case SPACEKEY:
1170                                 case RETKEY:
1171                                         loop=0;
1172                                         break;
1173                                 case XKEY:
1174                                         break;
1175                                 case ESCKEY:
1176                                 case RIGHTMOUSE:
1177                                         cancel=1;
1178                                         loop=0;
1179                                         break;
1180                                 default:
1181                                         arrows_move_cursor(event);
1182                                         break;
1183                                 };
1184                         }
1185                 }
1186
1187                 if (cancel) {
1188                         for (i=0; i<tvtot; i++) {
1189                                 tv[i].loc[0]=tv[i].oldloc[0];
1190                                 tv[i].loc[1]=tv[i].oldloc[1];
1191                         }
1192                 } else {
1193                         getmouseco_areawin (mvalc);
1194                         areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
1195
1196                         if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
1197                                 PIL_sleep_ms(1);
1198                         } else {
1199                                 for (i=0; i<tvtot; i++){
1200                                         tv[i].loc[0]=tv[i].oldloc[0];
1201
1202                                         switch (mode){
1203                                         case 'g':
1204                                                 deltax = cval[0]-sval[0];
1205                                                 fac= deltax;
1206                                                 
1207                                                 apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & AUTOGRABGRID);
1208
1209                                                 tv[i].loc[0]+=fac;
1210                                                 break;
1211                                         case 's':
1212                                                 startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
1213                                                 deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
1214                                                 fac= fabs(deltax/startx);
1215                                                 
1216                                                 apply_keyb_grid(&fac, 0.0, 0.2, 0.1, U.flag & AUTOSIZEGRID);
1217                 
1218                                                 if (invert){
1219                                                         if (i % 03 == 0){
1220                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
1221                                                         }
1222                                                         if (i % 03 == 2){
1223                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
1224                                                         }
1225         
1226                                                         fac*=-1;
1227                                                 }
1228                                                 startx= (G.scene->r.cfra);
1229                                         
1230                                                 tv[i].loc[0]-= startx;
1231                                                 tv[i].loc[0]*=fac;
1232                                                 tv[i].loc[0]+= startx;
1233                 
1234                                                 break;
1235                                         }
1236                                 }
1237                         }
1238         
1239                         if (mode=='s'){
1240                                 sprintf(str, "sizeX: %.3f", fac);
1241                                 headerprint(str);
1242                         }
1243                         else if (mode=='g'){
1244                                 sprintf(str, "deltaX: %.3f", fac);
1245                                 headerprint(str);
1246                         }
1247         
1248                         if (G.saction->lock){
1249                                 do_all_actions();
1250                                 allqueue (REDRAWVIEW3D, 0);
1251                                 allqueue (REDRAWACTION, 0);
1252                                 allqueue (REDRAWIPO, 0);
1253                                 allqueue(REDRAWNLA, 0);
1254                                 force_draw_all();
1255                         }
1256                         else {
1257                                 addqueue (curarea->win, REDRAWALL, 0);
1258                                 force_draw ();
1259                         }
1260                 }
1261                 
1262                 lastcval[0]= cval[0];
1263                 lastcval[1]= cval[1];
1264                 firsttime= 0;
1265         }
1266         
1267         /*              Update the curve */
1268         /*              Depending on the lock status, draw necessary views */
1269
1270         do_all_actions();
1271         remake_action_ipos(act);
1272         allqueue (REDRAWVIEW3D, 0);
1273         allqueue (REDRAWACTION, 0);
1274         allqueue(REDRAWNLA, 0);
1275         allqueue (REDRAWIPO, 0);
1276         MEM_freeN (tv);
1277 }
1278
1279 static void transform_meshchannel_keys(char mode, Key *key)
1280 {
1281         /* this is the function that determines what happens
1282          * to those little blocky rvk key things you have selected 
1283          * after you press a 'g' or an 's'. I'd love to say that
1284          * I have an intimate knowledge of all of what this function
1285          * is doing, but instead I'm just going to pretend.
1286          */
1287     TransVert *tv;
1288     int /*sel=0,*/  i;
1289     short       mvals[2], mvalc[2], cent[2];
1290     float       sval[2], cval[2], lastcval[2];
1291     short       cancel=0;
1292     float       fac=0.0F;
1293     int         loop=1;
1294     int         tvtot=0;
1295     float       deltax, startx;
1296     float       cenf[2];
1297     int         invert=0, firsttime=1;
1298     char        str[256];
1299
1300         /* count all of the selected beziers, and
1301          * set all 3 control handles to selected
1302          */
1303     tvtot=fullselect_ipo_keys(key->ipo);
1304     
1305     /* If nothing is selected, bail out 
1306          */
1307     if (!tvtot)
1308         return;
1309         
1310         
1311     /* Build the transvert structure 
1312          */
1313     tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
1314     tvtot=0;
1315
1316     tvtot = add_trans_ipo_keys(key->ipo, tv, tvtot);
1317
1318     /* Do the event loop 
1319          */
1320     cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2;
1321     cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2;
1322     areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]);
1323
1324     getmouseco_areawin (mvals);
1325     areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
1326
1327     startx=sval[0];
1328     while (loop) {
1329         /* Get the input
1330                  * If we're cancelling, reset transformations
1331                  * Else calc new transformation
1332                  * Perform the transformations 
1333                  */
1334         while (qtest()) {
1335             short val;
1336             unsigned short event= extern_qread(&val);
1337
1338             if (val) {
1339                 switch (event) {
1340                 case LEFTMOUSE:
1341                 case SPACEKEY:
1342                 case RETKEY:
1343                     loop=0;
1344                     break;
1345                 case XKEY:
1346                     break;
1347                 case ESCKEY:
1348                 case RIGHTMOUSE:
1349                     cancel=1;
1350                     loop=0;
1351                     break;
1352                 default:
1353                     arrows_move_cursor(event);
1354                     break;
1355                 };
1356             }
1357         }
1358         
1359         if (cancel) {
1360             for (i=0; i<tvtot; i++) {
1361                 tv[i].loc[0]=tv[i].oldloc[0];
1362                 tv[i].loc[1]=tv[i].oldloc[1];
1363             }
1364         } 
1365                 else {
1366             getmouseco_areawin (mvalc);
1367             areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
1368                         
1369             if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
1370                 PIL_sleep_ms(1);
1371             } else {
1372                 for (i=0; i<tvtot; i++){
1373                     tv[i].loc[0]=tv[i].oldloc[0];
1374
1375                     switch (mode){
1376                     case 'g':
1377                         deltax = cval[0]-sval[0];
1378                         fac= deltax;
1379                                                 
1380                         apply_keyb_grid(&fac, 0.0, 1.0, 0.1, 
1381                                         U.flag & AUTOGRABGRID);
1382
1383                         tv[i].loc[0]+=fac;
1384                         break;
1385                     case 's':
1386                         startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax
1387                                                      -curarea->winrct.xmin)/2);
1388                         deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax
1389                                                      -curarea->winrct.xmin)/2);
1390                         fac= fabs(deltax/startx);
1391                                                 
1392                         apply_keyb_grid(&fac, 0.0, 0.2, 0.1, 
1393                                         U.flag & AUTOSIZEGRID);
1394                 
1395                         if (invert){
1396                             if (i % 03 == 0){
1397                                 memcpy (tv[i].loc, tv[i].oldloc, 
1398                                         sizeof(tv[i+2].oldloc));
1399                             }
1400                             if (i % 03 == 2){
1401                                 memcpy (tv[i].loc, tv[i].oldloc, 
1402                                         sizeof(tv[i-2].oldloc));
1403                             }
1404                                                         
1405                             fac*=-1;
1406                         }
1407                         startx= (G.scene->r.cfra);
1408                         
1409                         tv[i].loc[0]-= startx;
1410                         tv[i].loc[0]*=fac;
1411                         tv[i].loc[0]+= startx;
1412                 
1413                         break;
1414                     }
1415                 }
1416             }
1417                         /* Display a message showing the magnitude of
1418                          * the grab/scale we are performing
1419                          */
1420             if (mode=='s'){
1421                 sprintf(str, "sizeX: %.3f", fac);
1422                 headerprint(str);
1423             }
1424             else if (mode=='g'){
1425                 sprintf(str, "deltaX: %.3f", fac);
1426                 headerprint(str);
1427             }
1428         
1429             if (G.saction->lock){
1430                                 /* doubt any of this code ever gets
1431                                  * executed, but it might in the
1432                                  * future
1433                                  */
1434                                  
1435                 do_all_actions();
1436                 allqueue (REDRAWVIEW3D, 0);
1437                 allqueue (REDRAWACTION, 0);
1438                 allqueue (REDRAWIPO, 0);
1439                 allqueue(REDRAWNLA, 0);
1440                 force_draw_all();
1441             }
1442             else {
1443                 addqueue (curarea->win, REDRAWALL, 0);
1444                 force_draw ();
1445             }
1446         }
1447                 
1448         lastcval[0]= cval[0];
1449         lastcval[1]= cval[1];
1450         firsttime= 0;
1451     }
1452         
1453         /* fix up the Ipocurves and redraw stuff
1454          */
1455     meshkey_do_redraw(key);
1456
1457     MEM_freeN (tv);
1458
1459         /* did you understand all of that? I pretty much understand
1460          * what it does, but the specifics seem a little weird and crufty.
1461          */
1462 }
1463
1464
1465 void deselect_actionchannel_keys (bAction *act, int test)
1466 {
1467         bActionChannel  *chan;
1468         bConstraintChannel *conchan;
1469         int             sel=1;;
1470
1471         if (!act)
1472                 return;
1473
1474         /* Determine if this is selection or deselection */
1475         
1476         if (test){
1477                 for (chan=act->chanbase.first; chan; chan=chan->next){
1478                         /* Test the channel ipos */
1479                         if (is_ipo_key_selected(chan->ipo)){
1480                                 sel = 0;
1481                                 break;
1482                         }
1483
1484                         /* Test the constraint ipos */
1485                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1486                                 if (is_ipo_key_selected(conchan->ipo)){
1487                                         sel = 0;
1488                                         break;
1489                                 }
1490                         }
1491
1492                         if (sel == 0)
1493                                 break;
1494                 }
1495         }
1496         else
1497                 sel=0;
1498         
1499         /* Set the flags */
1500         for (chan=act->chanbase.first; chan; chan=chan->next){
1501                 set_ipo_key_selection(chan->ipo, sel);
1502                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1503                         set_ipo_key_selection(conchan->ipo, sel);
1504         }
1505 }
1506
1507 void deselect_meshchannel_keys (Key *key, int test)
1508 {
1509         /* should deselect the rvk keys
1510          */
1511     int         sel=1;
1512
1513     /* Determine if this is selection or deselection */
1514     if (test){
1515         if (is_ipo_key_selected(key->ipo)){
1516             sel = 0;
1517         }
1518     }
1519     else {
1520         sel=0;
1521     }
1522         
1523     /* Set the flags */
1524     set_ipo_key_selection(key->ipo, sel);
1525 }
1526
1527 void deselect_actionchannels (bAction *act, int test)
1528 {
1529         bActionChannel *chan;
1530         bConstraintChannel *conchan;
1531         int                     sel=1;  
1532
1533         if (!act)
1534                 return;
1535
1536         /* See if we should be selecting or deselecting */
1537         if (test){
1538                 for (chan=act->chanbase.first; chan; chan=chan->next){
1539                         if (!sel)
1540                                 break;
1541
1542                         if (chan->flag & ACHAN_SELECTED){
1543                                 sel=0;
1544                                 break;
1545                         }
1546                         if (sel){
1547                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1548                                         if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1549                                                 sel=0;
1550                                                 break;
1551                                         }
1552                                 }
1553                         }
1554                 }
1555         }
1556         else
1557                 sel=0;
1558
1559         /* Now set the flags */
1560         for (chan=act->chanbase.first; chan; chan=chan->next){
1561                 select_poseelement_by_name(chan->name, sel);
1562
1563                 if (sel)
1564                         chan->flag |= ACHAN_SELECTED;
1565                 else
1566                         chan->flag &= ~ACHAN_SELECTED;
1567
1568                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1569                         if (sel)
1570                                 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1571                         else
1572                                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1573                 }
1574         }
1575
1576 }
1577
1578 static void hilight_channel (bAction *act, bActionChannel *chan, short select)
1579 {
1580         bActionChannel *curchan;
1581
1582         if (!act)
1583                 return;
1584
1585         for (curchan=act->chanbase.first; curchan; curchan=curchan->next){
1586                 if (curchan==chan && select)
1587                         curchan->flag |= ACHAN_HILIGHTED;
1588                 else
1589                         curchan->flag &= ~ACHAN_HILIGHTED;
1590         }
1591 }
1592
1593 /* select_mode = SELECT_REPLACE
1594  *             = SELECT_ADD
1595  *             = SELECT_SUBTRACT
1596  *             = SELECT_INVERT
1597  */
1598
1599 static int select_channel(bAction *act, bActionChannel *chan,
1600                           int selectmode) {
1601         /* Select the channel based on the selection mode
1602          */
1603         int flag;
1604
1605         switch (selectmode) {
1606         case SELECT_ADD:
1607                 chan->flag |= ACHAN_SELECTED;
1608                 break;
1609         case SELECT_SUBTRACT:
1610                 chan->flag &= ~ACHAN_SELECTED;
1611                 break;
1612         case SELECT_INVERT:
1613                 chan->flag ^= ACHAN_SELECTED;
1614                 break;
1615         }
1616         flag = (chan->flag & ACHAN_SELECTED) ? 1 : 0;
1617
1618         hilight_channel(act, chan, flag);
1619         select_poseelement_by_name(chan->name, flag);
1620
1621         return flag;
1622 }
1623
1624 static int select_constraint_channel(bAction *act, 
1625                                      bConstraintChannel *conchan, 
1626                                      int selectmode) {
1627         /* Select the constraint channel based on the selection mode
1628          */
1629         int flag;
1630
1631         switch (selectmode) {
1632         case SELECT_ADD:
1633                 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1634                 break;
1635         case SELECT_SUBTRACT:
1636                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1637                 break;
1638         case SELECT_INVERT:
1639                 conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
1640                 break;
1641         }
1642         flag = (conchan->flag & CONSTRAINT_CHANNEL_SELECT) ? 1 : 0;
1643
1644         return flag;
1645 }
1646
1647
1648 static void mouse_actionchannels(bAction *act, short *mval,
1649                                  short *mvalo, int selectmode) {
1650         /* Select action channels, based on mouse values.
1651          * If mvalo is NULL we assume it is a one click
1652          * action, other wise we treat it like it is a
1653          * border select with mval[0],mval[1] and
1654          * mvalo[0], mvalo[1] forming the corners of
1655          * a rectangle.
1656          */
1657         bActionChannel *chan;
1658         float   click;
1659         int   clickmin, clickmax;
1660         int             wsize, sel;
1661         bConstraintChannel *conchan;
1662
1663         if (!act)
1664                 return;
1665   
1666         if (selectmode == SELECT_REPLACE) {
1667                 deselect_actionchannels (act, 0);
1668                 selectmode = SELECT_ADD;
1669         }
1670
1671         /* wsize is the greatest possible height (in pixels) that would be
1672          * needed to draw all of the action channels and constraint
1673          * channels.
1674          */
1675         wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP));
1676
1677         click = (wsize-(mval[1]+G.v2d->cur.ymin));
1678         click += CHANNELHEIGHT/2;
1679         click /= (CHANNELHEIGHT+CHANNELSKIP);
1680         
1681         clickmin = (int) click;
1682
1683         /* Only one click */
1684         if (mvalo == NULL) {
1685                 clickmax = clickmin;
1686         }
1687         /* Two click values (i.e., border select */
1688         else {
1689                 click = (wsize-(mvalo[1]+G.v2d->cur.ymin));
1690                 click += CHANNELHEIGHT/2;
1691                 click /= (CHANNELHEIGHT+CHANNELSKIP);
1692
1693                 if ( ((int) click) < clickmin) {
1694                         clickmax = clickmin;
1695                         clickmin = (int) click;
1696                 }
1697                 else {
1698                         clickmax = (int) click;
1699                 }
1700         }
1701
1702         if (clickmax < 0) {
1703                 return;
1704         }
1705
1706         /* clickmin and clickmax now coorespond to indices into
1707          * the collection of channels and constraint channels.
1708          * What we need to do is apply the selection mode on all
1709          * channels and constraint channels between these indices.
1710          * This is done by traversing the channels and constraint
1711          * channels, for each item decrementing clickmin and clickmax.
1712          * When clickmin is less than zero we start selecting stuff,
1713          * until clickmax is less than zero or we run out of channels
1714          * and constraint channels.
1715          */
1716
1717         for (chan = act->chanbase.first; chan; chan=chan->next){
1718                 if (clickmax < 0) break;
1719
1720                 if ( clickmin <= 0) {
1721                         /* Select the channel with the given mode. If the
1722                          * channel is freshly selected then set it to the
1723                          * active channel for the action
1724                          */
1725                         sel = (chan->flag & ACHAN_SELECTED);
1726                         if ( select_channel(act, chan, selectmode) && !sel ) {
1727                                 act->achan = chan;
1728                         }
1729                 }
1730                 --clickmin;
1731                 --clickmax;
1732
1733                 /* Check for click in a constraint */
1734                 for (conchan=chan->constraintChannels.first; 
1735                          conchan; conchan=conchan->next){
1736                         if (clickmax < 0) break;
1737                         if ( clickmin <= 0) {
1738                                 select_constraint_channel(act, conchan, selectmode);
1739                         }
1740                         --clickmin;
1741                         --clickmax;
1742                 }
1743         }
1744
1745         allqueue (REDRAWIPO, 0);
1746         allqueue (REDRAWVIEW3D, 0);
1747         allqueue (REDRAWACTION, 0);
1748         allqueue (REDRAWNLA, 0);
1749 }
1750
1751 static void delete_meshchannel_keys(Key *key)
1752 {
1753         if (!okee("Erase selected keys"))
1754                 return;
1755
1756         delete_ipo_keys(key->ipo);
1757
1758         meshkey_do_redraw(key);
1759 }
1760
1761 static void delete_actionchannel_keys(void)
1762 {
1763         bAction *act;
1764         bActionChannel *chan;
1765         bConstraintChannel *conchan;
1766
1767         act = G.saction->action;
1768         if (!act)
1769                 return;
1770
1771         if (!okee("Erase selected keys"))
1772                 return;
1773
1774         for (chan = act->chanbase.first; chan; chan=chan->next){
1775
1776                 /* Check action channel keys*/
1777                 delete_ipo_keys(chan->ipo);
1778
1779                 /* Delete constraint channel keys */
1780                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1781                         delete_ipo_keys(conchan->ipo);
1782         }
1783
1784         remake_action_ipos (act);
1785         allspace(REMAKEIPO, 0);
1786         allqueue(REDRAWACTION, 0);
1787         allqueue(REDRAWIPO, 0);
1788         allqueue(REDRAWNLA, 0);
1789
1790 }
1791 static void delete_actionchannels (void)
1792 {
1793         bConstraintChannel *conchan=NULL, *nextconchan;
1794         bActionChannel *chan, *next;
1795         bAction *act;
1796         int freechan;
1797
1798         act=G.saction->action;
1799
1800         if (!act)
1801                 return;
1802
1803         for (chan=act->chanbase.first; chan; chan=chan->next){
1804                 if (chan->flag & ACHAN_SELECTED)
1805                         break;
1806                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1807                 {
1808                         if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1809                                 chan=act->chanbase.last;
1810                                 break;
1811                         }
1812                 }
1813         }
1814
1815         if (!chan && !conchan)
1816                 return;
1817
1818         if (!okee("Erase selected channels"))
1819                 return;
1820
1821         for (chan=act->chanbase.first; chan; chan=next){
1822                 freechan = 0;
1823                 next=chan->next;
1824                 
1825                 /* Remove action channels */
1826                 if (chan->flag & ACHAN_SELECTED){
1827                         if (chan->ipo)
1828                                 chan->ipo->id.us--;     /* Release the ipo */
1829                         freechan = 1;
1830                 }
1831                 
1832                 /* Remove constraint channels */
1833                 for (conchan=chan->constraintChannels.first; conchan; conchan=nextconchan){
1834                         nextconchan=conchan->next;
1835                         if (freechan || conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1836                                 if (conchan->ipo)
1837                                         conchan->ipo->id.us--;
1838                                 BLI_freelinkN(&chan->constraintChannels, conchan);
1839                         }
1840                 }
1841                 
1842                 if (freechan)
1843                         BLI_freelinkN (&act->chanbase, chan);
1844
1845         }
1846
1847         allqueue (REDRAWACTION, 0);
1848         allqueue(REDRAWNLA, 0);
1849
1850 }
1851
1852 static void sethandles_meshchannel_keys(int code, Key *key)
1853 {
1854     sethandles_ipo_keys(key->ipo, code);
1855
1856         meshkey_do_redraw(key);
1857 }
1858
1859 static void sethandles_actionchannel_keys(int code)
1860 {
1861         bAction *act;
1862         bActionChannel *chan;
1863
1864         /* Get the selected action, exit if none are selected 
1865          */
1866         act = G.saction->action;
1867         if (!act)
1868                 return;
1869
1870         /* Loop through the channels and set the beziers
1871          * of the selected keys based on the integer code
1872          */
1873         for (chan = act->chanbase.first; chan; chan=chan->next){
1874                 sethandles_ipo_keys(chan->ipo, code);
1875         }
1876
1877         /* Clean up and redraw stuff
1878          */
1879         remake_action_ipos (act);
1880         allspace(REMAKEIPO, 0);
1881         allqueue(REDRAWACTION, 0);
1882         allqueue(REDRAWIPO, 0);
1883         allqueue(REDRAWNLA, 0);
1884 }
1885
1886 static void set_ipotype_actionchannels(void) {
1887
1888         bAction *act; 
1889         bActionChannel *chan;
1890         short event;
1891
1892         /* Get the selected action, exit if none are selected 
1893          */
1894         act = G.saction->action;
1895         if (!act)
1896                 return;
1897
1898         /* Present a popup menu asking the user what type
1899          * of IPO curve he/she/GreenBTH wants. ;)
1900          */
1901         event= pupmenu("Channel Ipo Type %t|Constant %x1|Linear %x2|Bezier %x3");
1902         if(event < 1) return;
1903         
1904         /* Loop through the channels and for the selected ones set
1905          * the type for each Ipo curve in the channel Ipo (based on
1906          * the value from the popup).
1907          */
1908         for (chan = act->chanbase.first; chan; chan=chan->next){
1909                 if (chan->flag & ACHAN_SELECTED){
1910                         if (chan->ipo)
1911                                 setipotype_ipo(chan->ipo, event);
1912                 }
1913         }
1914
1915         /* Clean up and redraw stuff
1916          */
1917         remake_action_ipos (act);
1918         allspace(REMAKEIPO, 0);
1919         allqueue(REDRAWACTION, 0);
1920         allqueue(REDRAWIPO, 0);
1921         allqueue(REDRAWNLA, 0);
1922 }
1923
1924 void select_all_keys_frames(bAction *act, short *mval, 
1925                                                         short *mvalo, int selectmode) {
1926         
1927         /* This function tries to select all action keys in
1928          * every channel for a given range of keyframes that
1929          * are within the mouse values mval and mvalo (usually
1930          * the result of a border select). If mvalo is passed as
1931          * NULL then the selection is treated as a one-click and
1932          * the function tries to select all keys within half a
1933          * frame of the click point.
1934          */
1935         
1936         rcti rect;
1937         rctf rectf;
1938         bActionChannel *chan;
1939         bConstraintChannel *conchan;
1940
1941         if (!act)
1942                 return;
1943
1944         if (selectmode == SELECT_REPLACE) {
1945                 deselect_actionchannel_keys(act, 0);
1946                 selectmode = SELECT_ADD;
1947         }
1948
1949         if (mvalo == NULL) {
1950                 rect.xmin = rect.xmax = mval[0];
1951                 rect.ymin = rect.ymax = mval[1];
1952         }
1953         else {
1954                 if (mval[0] < mvalo[0] ) {
1955                         rect.xmin = mval[0];
1956                         rect.xmax = mvalo[0];
1957                 }
1958                 else {
1959                         rect.xmin = mvalo[0];
1960                         rect.xmax = mval[0];
1961                 }
1962                 if (mval[1] < mvalo[1] ) {
1963                         rect.ymin = mval[1];
1964                         rect.ymax = mvalo[1];
1965                 }
1966                 else {
1967                         rect.ymin = mvalo[1];
1968                         rect.ymax = mval[1];
1969                 }
1970         }
1971
1972         mval[0]= rect.xmin;
1973         mval[1]= rect.ymin+2;
1974         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1975         mval[0]= rect.xmax;
1976         mval[1]= rect.ymax-2;
1977         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1978
1979         if (mvalo == NULL) {
1980                 rectf.xmin = rectf.xmin - 0.5;
1981                 rectf.xmax = rectf.xmax + 0.5;
1982         }
1983     
1984         for (chan=act->chanbase.first; chan; chan=chan->next){
1985                 borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax,
1986                                                          selectmode);
1987                 for (conchan=chan->constraintChannels.first; conchan; 
1988                          conchan=conchan->next){
1989                         borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
1990                                                                  selectmode);
1991                 }
1992         }       
1993         allqueue(REDRAWNLA, 0);
1994         allqueue(REDRAWACTION, 0);
1995         allqueue(REDRAWIPO, 0);
1996 }
1997
1998
1999 void select_all_keys_channels(bAction *act, short *mval, 
2000                               short *mvalo, int selectmode) {
2001         bActionChannel    *chan;
2002         float              click;
2003         int                clickmin, clickmax;
2004         int                wsize;
2005         bConstraintChannel *conchan;
2006
2007         /* This function selects all the action keys that
2008          * are in the mouse selection range defined by
2009          * the ordered pairs mval and mvalo (usually
2010          * these 2 are obtained from a border select).
2011          * If mvalo is NULL, then the selection is
2012          * treated like a one-click action, and at most
2013          * one channel is selected.
2014          */
2015
2016         /* If the action is null then abort
2017          */
2018         if (!act)
2019                 return;
2020
2021         if (selectmode == SELECT_REPLACE) {
2022                 deselect_actionchannel_keys(act, 0);
2023                 selectmode = SELECT_ADD;
2024         }
2025
2026         /* wsize is the greatest possible height (in pixels) that would be
2027          * needed to draw all of the action channels and constraint
2028          * channels.
2029          */
2030         wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP));
2031
2032         click = (wsize-(mval[1]+G.v2d->cur.ymin));
2033         click += CHANNELHEIGHT/2;
2034         click /= (CHANNELHEIGHT+CHANNELSKIP);
2035
2036         clickmin = (int) click;
2037
2038         /* Only one click */
2039         if (mvalo == NULL) {
2040                 clickmax = clickmin;
2041         }
2042         /* Two click values (i.e., border select) */
2043         else {
2044                 click = (wsize-(mvalo[1]+G.v2d->cur.ymin));
2045                 click += CHANNELHEIGHT/2;
2046                 click /= (CHANNELHEIGHT+CHANNELSKIP);
2047
2048                 if ( ((int) click) < clickmin) {
2049                         clickmax = clickmin;
2050                         clickmin = (int) click;
2051                 }
2052                 else {
2053                         clickmax = (int) click;
2054                 }
2055         }
2056
2057         if (clickmax < 0) {
2058                 return;
2059         }
2060
2061         for (chan = act->chanbase.first; chan; chan=chan->next){
2062                 if (clickmax < 0) break;
2063
2064                 if ( clickmin <= 0) {
2065                         /* Select the channel with the given mode. If the
2066                          * channel is freshly selected then set it to the
2067                          * active channel for the action
2068                          */
2069                         select_ipo_bezier_keys(chan->ipo, selectmode);
2070                 }
2071                 --clickmin;
2072                 --clickmax;
2073
2074                 /* Check for click in a constraint */
2075                 for (conchan=chan->constraintChannels.first; 
2076                          conchan; conchan=conchan->next){
2077                         if (clickmax < 0) break;
2078                         if ( clickmin <= 0) {
2079                                 select_ipo_bezier_keys(chan->ipo, selectmode);
2080                         }
2081                         --clickmin;
2082                         --clickmax;
2083                 }
2084         }
2085   
2086         allqueue (REDRAWIPO, 0);
2087         allqueue (REDRAWVIEW3D, 0);
2088         allqueue (REDRAWACTION, 0);
2089         allqueue (REDRAWNLA, 0);
2090   
2091 }
2092
2093 static void borderselect_function(void (*select_func)(bAction *act, 
2094                                                      short *mval, 
2095                                                      short *mvalo, 
2096                                                      int selectmode)) {
2097         /* This function executes an arbitrary selection
2098          * function as part of a border select. This
2099          * way the same function that is used for
2100          * right click selection points can generally
2101          * be used as the argument to this function
2102          */
2103         rcti rect;
2104         short   mval[2], mvalo[2];
2105         bAction *act;
2106         int val;                
2107
2108         /* Get the selected action, exit if none are selected 
2109          */
2110         act=G.saction->action;
2111         if (!act)
2112                 return;
2113
2114         /* Let the user draw a border (or abort)
2115          */
2116         if ( (val=get_border (&rect, 3)) ) {
2117                 mval[0]= rect.xmin;
2118                 mval[1]= rect.ymin+2;
2119                 mvalo[0]= rect.xmax;
2120                 mvalo[1]= rect.ymax-2;
2121
2122                 /* if the left mouse was used, do an additive
2123                  * selection with the user defined selection
2124                  * function.
2125                  */
2126                 if (val == LEFTMOUSE)
2127                         select_func(act, mval, mvalo, SELECT_ADD);
2128                 
2129                 /* if the right mouse was used, do a subtractive
2130                  * selection with the user defined selection
2131                  * function.
2132                  */
2133                 else if (val == RIGHTMOUSE)
2134                         select_func(act, mval, mvalo, SELECT_SUBTRACT);
2135         }
2136         
2137 }
2138
2139 void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
2140 {
2141         unsigned short event= evt->event;
2142         short val= evt->val;
2143         SpaceAction *saction;
2144         bAction *act;
2145         int doredraw= 0;
2146         short   mval[2];
2147         float dx,dy;
2148         int     cfra;
2149         Key *key;
2150
2151         if(curarea->win==0) return;
2152
2153         saction= curarea->spacedata.first;
2154         if (!saction)
2155                 return;
2156
2157         act=saction->action;
2158         if(val) {
2159                 
2160                 if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
2161                 
2162                 getmouseco_areawin(mval);
2163
2164                 key = get_action_mesh_key();
2165
2166                 switch(event) {
2167                 case UI_BUT_EVENT:
2168                         do_butspace(val); // abuse!
2169                         break;
2170                 case HOMEKEY:
2171                         do_action_buttons(B_ACTHOME);
2172                         break;
2173
2174                 case CKEY:
2175                         /* scroll the window so the current
2176                          * frame is in the center.
2177                          */
2178                         center_currframe();
2179                         break;
2180
2181                 case DKEY:
2182                         if (key) {
2183                                 if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH) {
2184                                         duplicate_meshchannel_keys(key);
2185                                 }
2186                         }
2187                         else {
2188                                 if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH){
2189                                         duplicate_actionchannel_keys();
2190                                         remake_action_ipos(act);
2191                                 }
2192                         }
2193                         break;
2194
2195                 case DELKEY:
2196
2197                 case XKEY:
2198                         if (key) {
2199                                 delete_meshchannel_keys(key);
2200                         }
2201                         else {
2202                                 if (mval[0]<NAMEWIDTH)
2203                                         delete_actionchannels ();
2204                                 else
2205                                         delete_actionchannel_keys ();
2206                         }
2207                         break;
2208
2209                 case GKEY:
2210                         if (mval[0]>=ACTWIDTH) {
2211                                 if (key) {
2212                                         transform_meshchannel_keys('g', key);
2213                                 }
2214                                 else {
2215                                         transform_actionchannel_keys ('g');
2216                                 }
2217                         }
2218                         break;
2219
2220                 case SKEY:
2221                         if (mval[0]>=ACTWIDTH) {
2222                                 if (key) {
2223                                         transform_meshchannel_keys('s', key);
2224                                 }
2225                                 else {
2226                                         transform_actionchannel_keys ('s');
2227                                 }
2228                         }
2229                         break;
2230
2231                 case AKEY:
2232                         if (key) {
2233                                 if (mval[0]<ACTWIDTH){
2234                                         /* to do ??? */
2235                                 }
2236                                 else{
2237                                         deselect_meshchannel_keys(key, 1);
2238                                         allqueue (REDRAWACTION, 0);
2239                                         allqueue(REDRAWNLA, 0);
2240                                         allqueue (REDRAWIPO, 0);
2241                                 }
2242                         }
2243                         else {
2244                                 if (mval[0]<NAMEWIDTH){
2245                                         deselect_actionchannels (act, 1);
2246                                         allqueue (REDRAWVIEW3D, 0);
2247                                         allqueue (REDRAWACTION, 0);
2248                                         allqueue(REDRAWNLA, 0);
2249                                         allqueue (REDRAWIPO, 0);
2250                                 }
2251                                 else if (mval[0]>ACTWIDTH){
2252                                         deselect_actionchannel_keys (act, 1);
2253                                         allqueue (REDRAWACTION, 0);
2254                                         allqueue(REDRAWNLA, 0);
2255                                         allqueue (REDRAWIPO, 0);
2256                                 }
2257                         }
2258                         break;
2259
2260                 case VKEY:
2261                         if (key) {
2262                                 sethandles_meshchannel_keys(HD_VECT, key);
2263                                 /* to do */
2264                         }
2265                         else {
2266                                 sethandles_actionchannel_keys(HD_VECT);
2267                         }
2268                         break;
2269                 case HKEY:
2270                         if (key) {
2271                                 if(G.qual & LR_SHIFTKEY) {
2272                                         sethandles_meshchannel_keys(HD_AUTO, key);
2273                                 }
2274                                 else { 
2275                                         sethandles_meshchannel_keys(HD_ALIGN, key);
2276                                 }
2277                         }
2278                         else {
2279                                 if(G.qual & LR_SHIFTKEY) {
2280                                         sethandles_actionchannel_keys(HD_AUTO);
2281                                 }
2282                                 else { 
2283                                         sethandles_actionchannel_keys(HD_ALIGN);
2284                                 }
2285                         }
2286                         break;
2287
2288                         /*** set the Ipo type  ***/
2289                 case TKEY:
2290                         if (key) {
2291                                 /* to do */
2292                         }
2293                         else {
2294                                 set_ipotype_actionchannels();
2295                         }
2296                         break;
2297
2298                 case BKEY:
2299                         if (key) {
2300                                 if (mval[0]<ACTWIDTH){
2301                                         /* to do?? */
2302                                 }
2303                                 else {
2304                                         borderselect_mesh(key);
2305                                 }
2306                         }
2307                         else {
2308
2309                                 /* If the border select is initiated in the
2310                                  * part of the action window where the channel
2311                                  * names reside, then select the channels
2312                                  */
2313                                 if (mval[0]<NAMEWIDTH){
2314                                         borderselect_function(mouse_actionchannels);
2315                                 }
2316                                 else if (mval[0]>ACTWIDTH){
2317
2318                                         /* If the border select is initiated in the
2319                                          * vertical scrollbar, then (de)select all keys
2320                                          * for the channels in the selection region
2321                                          */
2322                                         if (IN_2D_VERT_SCROLL(mval)) {
2323                                                 borderselect_function(select_all_keys_channels);
2324                                         }
2325
2326                                         /* If the border select is initiated in the
2327                                          * horizontal scrollbar, then (de)select all keys
2328                                          * for the keyframes in the selection region
2329                                          */
2330                                         else if (IN_2D_HORIZ_SCROLL(mval)) {
2331                                                 borderselect_function(select_all_keys_frames);
2332                                         }
2333
2334                                         /* Other wise, select the action keys
2335                                          */
2336                                         else {
2337                                                 borderselect_action();
2338                                         }
2339                                 }
2340                         }
2341                         break;
2342
2343                 case RIGHTMOUSE:
2344                         /* Right clicking in the channel area selects the
2345                          * channel or constraint channel
2346                          */
2347                         if (mval[0]<NAMEWIDTH) {
2348                                 if(G.qual & LR_SHIFTKEY)
2349                                         mouse_actionchannels(act, mval, NULL, 
2350                                                                                  SELECT_INVERT);
2351                                 else
2352                                         mouse_actionchannels(act, mval, NULL, 
2353                                                                                  SELECT_REPLACE);
2354                         }
2355                         else if (mval[0]>ACTWIDTH) {
2356
2357                                 /* Right clicking in the vertical scrollbar selects
2358                                  * all of the keys for that channel at that height
2359                                  */
2360                                 if (IN_2D_VERT_SCROLL(mval)) {
2361                                         if(G.qual & LR_SHIFTKEY)
2362                                                 select_all_keys_channels(act, mval, NULL, 
2363                                                                                                  SELECT_INVERT);
2364                                         else
2365                                                 select_all_keys_channels(act, mval, NULL, 
2366                                                                                                  SELECT_REPLACE);
2367                                 }
2368
2369                                 /* Right clicking in the horizontal scrollbar selects
2370                                  * all of the keys within 0.5 of the nearest integer
2371                                  * frame
2372                                  */
2373                                 else if (IN_2D_HORIZ_SCROLL(mval)) {
2374                                         if(G.qual & LR_SHIFTKEY)
2375                                                 select_all_keys_frames(act, mval, NULL, 
2376                                                                                            SELECT_INVERT);
2377                                         else
2378                                                 select_all_keys_frames(act, mval, NULL, 
2379                                                                                            SELECT_REPLACE);
2380                                 }
2381                                 
2382                                 /* Clicking in the main area of the action window
2383                                  * selects keys
2384                                  */
2385                                 else {
2386                                         if (key) {
2387                                                 if(G.qual & LR_SHIFTKEY)
2388                                                         mouse_mesh_action(SELECT_INVERT, key);
2389                                                 else
2390                                                         mouse_mesh_action(SELECT_REPLACE, key);
2391                                         }
2392                                         else {
2393                                                 if(G.qual & LR_SHIFTKEY)
2394                                                         mouse_action(SELECT_INVERT);
2395                                                 else
2396                                                         mouse_action(SELECT_REPLACE);
2397                                         }
2398                                 }
2399                         }
2400                         break;
2401
2402                 case LEFTMOUSE:
2403                         if (mval[0]>ACTWIDTH){
2404                                 do {
2405                                         getmouseco_areawin(mval);
2406                                         
2407                                         areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
2408                                         
2409                                         cfra= (int)dx;
2410                                         if(cfra< 1) cfra= 1;
2411                                         
2412                                         if( cfra!=CFRA ) {
2413                                                 CFRA= cfra;
2414                                                 update_for_newframe();
2415                                                 force_draw_plus(SPACE_VIEW3D);
2416                                                 force_draw_plus(SPACE_IPO);
2417                                                 force_draw_plus(SPACE_BUTS);
2418                                         }
2419                                         
2420                                 } while(get_mbut()&L_MOUSE);
2421                         }
2422                         
2423                         break;
2424                 case MIDDLEMOUSE:
2425                 case WHEELUPMOUSE:
2426                 case WHEELDOWNMOUSE:
2427                         view2dmove(event);      /* in drawipo.c */
2428                         break;
2429                 }
2430         }
2431
2432         if(doredraw) addqueue(curarea->win, REDRAW, 1);
2433         
2434 }
2435
2436 Key *get_action_mesh_key(void) {
2437         /* gets the key data from the currently selected
2438          * mesh/lattice. If a mesh is not selected, or does not have
2439          * key data, then we return NULL (currently only
2440          * returns key data for RVK type meshes). If there
2441          * is an action that is pinned, return null
2442          */
2443     Object *ob;
2444     Key    *key;
2445
2446     ob = OBACT;
2447     if (!ob) return NULL;
2448
2449         if (G.saction->pin) return NULL;
2450
2451     if (ob->type==OB_MESH ) {
2452                 key = ((Mesh *)ob->data)->key;
2453     }
2454         else if (ob->type==OB_LATTICE ) {
2455                 key = ((Lattice *)ob->data)->key;
2456         }
2457         else return NULL;
2458
2459         if (key) {
2460                 if (key->type == KEY_RELATIVE)
2461                         return key;
2462         }
2463
2464     return NULL;
2465 }
2466
2467 int get_nearest_key_num(Key *key, short *mval, float *x) {
2468         /* returns the key num that cooresponds to the
2469          * y value of the mouse click. Does not check
2470          * if this is a valid keynum. Also gives the Ipo
2471          * x coordinate.
2472          */
2473     int num;
2474     float ybase, y;
2475
2476     areamouseco_to_ipoco(G.v2d, mval, x, &y);
2477
2478     ybase = key->totkey * (CHANNELHEIGHT + CHANNELSKIP);
2479     num = (int) ((ybase - y) / (CHANNELHEIGHT+CHANNELSKIP));
2480
2481     return (num + 1);
2482 }
2483
2484 static void clever_keyblock_names(Key *key, short* mval){
2485     int        but=0, i, keynum;
2486     char       str[64];
2487         float      x;
2488         KeyBlock   *kb;
2489         /* get the keynum cooresponding to the y value
2490          * of the mouse pointer, return if this is
2491          * an invalid key number (and we don't deal
2492          * with the speed ipo).
2493          */
2494
2495     keynum = get_nearest_key_num(key, mval, &x);
2496     if ( (keynum < 1) || (keynum >= key->totkey) )
2497         return;
2498
2499         kb= key->block.first;
2500         for (i=0; i<keynum; ++i) kb = kb->next; 
2501
2502         if (kb->name[0] == '\0') {
2503                 sprintf(str, "Key %d", keynum);
2504         }
2505         else {
2506                 strcpy(str, kb->name);
2507         }
2508
2509         if ( (kb->slidermin >= kb->slidermax) ) {
2510                 kb->slidermin = 0.0;
2511                 kb->slidermax = 1.0;
2512         }
2513
2514     add_numbut(but++, TEX, "KB: ", 0, 24, str, 
2515                "Does this really need a tool tip?");
2516         add_numbut(but++, NUM|FLO, "Slider min:", 
2517                            -10000, kb->slidermax, &kb->slidermin, 0);
2518         add_numbut(but++, NUM|FLO, "Slider max:", 
2519                            kb->slidermin, 10000, &kb->slidermax, 0);
2520
2521     if (do_clever_numbuts(str, but, REDRAW)) {
2522                 strcpy(kb->name, str);
2523         allqueue (REDRAWACTION, 0);
2524         allqueue (REDRAWIPO, 0);
2525         }
2526
2527         
2528 }
2529
2530 void stupid_damn_numbuts_action(void){
2531     /* I think this function might have been
2532      * deemed clever if it could have been
2533      * called from the event processing
2534      * routine in this file -- rather than having
2535      * to go from the NKEY event from blenderqread
2536      * in toets.c (which returns 0 so nobody else
2537      * can use the NKEY) then into the clever_numbuts
2538      * routine in toolbox.c, the finally to this
2539      * function. Grumble, grumble, grumble ...
2540      */
2541
2542     Key *key;
2543     short mval[2];
2544
2545     if ( (key = get_action_mesh_key()) ) {
2546         getmouseco_areawin (mval);
2547                 if (mval[0]<NAMEWIDTH) {
2548                         clever_keyblock_names(key, mval);
2549                 }
2550     }
2551 }