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