Update things to use blender_test_break() vs MISC_test_break() and
[blender.git] / source / blender / src / editaction.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <string.h>
34 #include <math.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #ifdef WIN32
41 #include "BLI_winstuff.h"
42 #endif
43
44 #include "MEM_guardedalloc.h"
45
46 #include "PIL_time.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
50
51 #include "DNA_action_types.h"
52 #include "DNA_armature_types.h"
53 #include "DNA_curve_types.h"
54 #include "DNA_ipo_types.h"
55 #include "DNA_object_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_screen_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_constraint_types.h"
60
61 #include "BKE_armature.h"
62 #include "BKE_constraint.h"
63 #include "BKE_displist.h"
64 #include "BKE_curve.h"
65 #include "BKE_ipo.h"
66 #include "BKE_global.h"
67 #include "BKE_library.h"
68 #include "BKE_main.h"
69 #include "BKE_action.h"
70
71 #include "BIF_gl.h"
72 #include "BIF_mywindow.h"
73 #include "BIF_toolbox.h"
74 #include "BIF_screen.h"
75 #include "BIF_space.h"
76 #include "BIF_buttons.h"
77 #include "BIF_interface.h"
78 #include "BIF_editview.h"
79 #include "BIF_poseobject.h"
80 #include "BIF_editarmature.h"
81
82 #include "BSE_edit.h"
83 #include "BSE_drawipo.h"
84 #include "BSE_headerbuttons.h"
85 #include "BSE_editipo.h"
86 #include "BSE_editaction.h"
87 #include "BSE_trans_types.h"
88 #include "BSE_editaction_types.h"
89
90 #include "BDR_editobject.h"
91
92 #include "interface.h"
93 #include "mydevice.h"
94 #include "blendef.h"
95 #include "nla.h"
96
97 static bPose    *g_posebuf=NULL;
98 extern int count_action_levels (bAction *act);
99
100 #define BEZSELECTED(bezt)   (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1))
101
102 /* Local Function prototypes */
103
104 static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float time);
105 static void flip_name (char *name);
106 static void mouse_actionchannels(bAction *act, short *mval, 
107                                  short *mvalo, int selectmode);
108 static void borderselect_action(void);
109 static void mouse_action(int selectmode);
110 static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **conchan);
111 static void delete_actionchannels(void);
112 static void delete_actionchannel_keys(void);
113 static void duplicate_actionchannel_keys(void);
114 static void transform_actionchannel_keys(char mode);
115 static void select_poseelement_by_name (char *name, int select);
116 static void hilight_channel (bAction *act, bActionChannel *chan, short hilight);
117 static void set_action_key_time (bAction *act, bPoseChannel *chan, int adrcode, short makecurve, float time);
118
119 /* Implementation */
120
121 static void select_poseelement_by_name (char *name, int select)
122 {
123         /* Synchs selection of channels with selection of object elements in posemode */
124
125         Object *ob;
126
127         ob = G.obpose;
128         if (!ob)
129                 return;
130
131         switch (ob->type){
132         case OB_ARMATURE:
133                 select_bone_by_name ((bArmature*)ob->data, name, select);
134                 break;
135         default:
136                 break;
137         }
138 }
139 #ifdef __NLA_BAKE
140 bAction* bake_action_with_client (bAction *act, Object *armob, float tolerance)
141 {
142         bAction                 *result=NULL;
143         bActionChannel *achan;
144         float                   actlen;
145         int                             curframe;
146         char                    newname[64];
147         bArmature               *arm;
148         Bone                    *bone;
149         float                   oldframe;
150         bAction                 *temp;
151         bPoseChannel *pchan;
152
153         if (!act)
154                 return NULL;
155
156         arm = get_armature(armob);
157
158         
159         if (G.obedit){
160                 error ("Not in editmode");
161                 return NULL;
162         }
163
164         if (!arm){
165                 error ("Must have an armature selected");
166                 return NULL;
167         }
168         /* Get a new action */
169         result = add_empty_action();
170
171         /* Assign the new action a unique name */
172         sprintf (newname, "%s.BAKED", act->id.name+2);
173         rename_id(&result->id, newname);
174
175         actlen = calc_action_end(act);
176
177         oldframe = G.scene->r.cfra;
178
179         temp = armob->action;
180         armob->action = act;
181         
182         for (curframe=1; curframe<ceil(actlen+1); curframe++){
183
184                 /* Apply the old action */
185                 
186                 G.scene->r.cfra = curframe;
187
188                 /* Apply the object ipo */
189                 get_pose_from_action(&armob->pose, act, curframe);
190                 apply_pose_armature(arm, armob->pose, 1);
191                 clear_object_constraint_status(armob);
192                 where_is_armature_time(armob, curframe);
193                 
194                 /* For each channel: set avail keys with current values */
195                 for (pchan=armob->pose->chanbase.first; pchan; pchan=pchan->next){      
196
197                         /* Copy the constraints from the armature (if any) */
198
199                         bone = get_named_bone(arm, pchan->name);
200                         if (bone){
201
202                                 Mat4ToQuat(pchan->obmat, pchan->quat);
203                                 Mat4ToSize(pchan->obmat, pchan->size);
204                                 VECCOPY(pchan->loc, pchan->obmat[3]);
205                         
206                                 /* Apply to keys */      
207                                 set_action_key_time (result, pchan, AC_QUAT_X, 1, curframe);
208                                 set_action_key_time (result, pchan, AC_QUAT_Y, 1, curframe);
209                                 set_action_key_time (result, pchan, AC_QUAT_Z, 1, curframe);
210                                 set_action_key_time (result, pchan, AC_QUAT_W, 1, curframe);
211                                 set_action_key_time (result, pchan, AC_LOC_X, 1, curframe);
212                                 set_action_key_time (result, pchan, AC_LOC_Y, 1, curframe);
213                                 set_action_key_time (result, pchan, AC_LOC_Z, 1, curframe);
214                         }
215                 }
216         }
217
218         /* Make another pass to ensure all keyframes are set to linear interpolation mode */
219         for (achan = result->chanbase.first; achan; achan=achan->next){
220                 IpoCurve* icu;
221                 for (icu = achan->ipo->curve.first; icu; icu=icu->next){
222                         icu->ipo= IPO_LIN;
223                 }
224         }
225
226         notice ("Made new action \"%s\"", newname);
227         G.scene->r.cfra = oldframe;
228         armob->action = temp;
229         return result;
230 }
231 #endif
232
233 void select_actionchannel_by_name (bAction *act, char *name, int select)
234 {
235         bActionChannel *chan;
236
237         if (!act)
238                 return;
239
240         for (chan = act->chanbase.first; chan; chan=chan->next){
241                 if (!strcmp (chan->name, name)){
242                         act->achan = chan;
243                         if (select){
244                                 chan->flag |= ACHAN_SELECTED;
245                                 hilight_channel (act, chan, 1);
246                         }
247                         else{
248                                 chan->flag &= ~ACHAN_SELECTED;
249                                 hilight_channel (act, chan, 0);
250                         }
251                         return;
252                 }
253         }
254 }
255
256 void remake_action_ipos(bAction *act)
257 {
258         bActionChannel *chan;
259         bConstraintChannel *conchan;
260         IpoCurve                *icu;
261
262         for (chan= act->chanbase.first; chan; chan=chan->next){
263                 if (chan->ipo){
264                         for (icu = chan->ipo->curve.first; icu; icu=icu->next){
265                                 sort_time_ipocurve(icu);
266                                 testhandles_ipocurve(icu);
267                         }
268                 }
269                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
270                         if (conchan->ipo){
271                                 for (icu = conchan->ipo->curve.first; icu; icu=icu->next){
272                                         sort_time_ipocurve(icu);
273                                         testhandles_ipocurve(icu);
274                                 }
275                         }
276                 }
277         }
278 }
279
280 static void duplicate_actionchannel_keys(void)
281 {
282         bAction *act;
283         bActionChannel *chan;
284         bConstraintChannel *conchan;
285
286         act=G.saction->action;
287         if (!act)
288                 return;
289
290         /* Find selected items */
291         for (chan = act->chanbase.first; chan; chan=chan->next){
292                 duplicate_ipo_keys(chan->ipo);
293                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
294                         duplicate_ipo_keys(conchan->ipo);
295         }
296
297         transform_actionchannel_keys ('g');
298 }
299
300 static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **rchan){
301         bAction *act;
302         bActionChannel *chan;
303         IpoCurve *icu;
304         bActionChannel *firstchan=NULL;
305         bConstraintChannel *conchan, *firstconchan=NULL;
306         int     foundsel=0;
307         float firstvert=-1, foundx=-1;
308                 int i;
309         short mval[2];
310         float ymin, ymax;
311         rctf    rectf;
312         *index=0;
313
314         *rchan=NULL;
315         act=G.saction->action; /* We presume that we are only called during a valid action */
316         
317         getmouseco_areawin (mval);
318
319         mval[0]-=7;
320         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
321
322         mval[0]+=14;
323         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
324
325         ymax = count_action_levels (act) * (CHANNELHEIGHT + CHANNELSKIP);
326
327         *sel=0;
328
329         for (chan=act->chanbase.first; chan; chan=chan->next){
330
331                 /* Check action channel */
332                 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
333                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
334                         for (icu=chan->ipo->curve.first; icu; icu=icu->next){
335                                 for (i=0; i<icu->totvert; i++){
336                                         if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
337                                                 if (!firstchan){
338                                                         firstchan=chan;
339                                                         firstvert=icu->bezt[i].vec[1][0];
340                                                         *sel = icu->bezt[i].f2 & 1;     
341                                                 }
342                                                 
343                                                 if (icu->bezt[i].f2 & 1){ 
344                                                         if (!foundsel){
345                                                                 foundsel=1;
346                                                                 foundx = icu->bezt[i].vec[1][0];
347                                                         }
348                                                 }
349                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
350                                                         *index=icu->bezt[i].vec[1][0];
351                                                         *sel = 0;
352                                                         return chan;
353                                                 }
354                                         }
355                                 }
356                         }
357                 }
358                 ymax=ymin;
359                 
360                 /* Check constraint channels */
361                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
362                         ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
363                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
364                                 for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
365                                         for (i=0; i<icu->totvert; i++){
366                                                 if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
367                                                         if (!firstchan){
368                                                                 firstchan=chan;
369                                                                 firstconchan=conchan;
370                                                                 firstvert=icu->bezt[i].vec[1][0];
371                                                                 *sel = icu->bezt[i].f2 & 1;     
372                                                         }
373                                                         
374                                                         if (icu->bezt[i].f2 & 1){ 
375                                                                 if (!foundsel){
376                                                                         foundsel=1;
377                                                                         foundx = icu->bezt[i].vec[1][0];
378                                                                 }
379                                                         }
380                                                         else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
381                                                                 *index=icu->bezt[i].vec[1][0];
382                                                                 *sel = 0;
383                                                                 *rchan = conchan;
384                                                                 return chan;
385                                                         }
386                                                 }
387                                         }
388                                 }
389                         }
390                         ymax=ymin;
391                 }
392         }       
393         
394         *rchan = firstconchan;
395         *index=firstvert;
396         return firstchan;
397 }
398
399 static void mouse_action(int selectmode)
400 {
401         bAction *act;
402         short sel;
403         float   selx;
404         bActionChannel *chan;
405         bConstraintChannel *conchan;
406         short   mval[2];
407
408         act=G.saction->action;
409         if (!act)
410                 return;
411
412         getmouseco_areawin (mval);
413
414         chan=get_nearest_actionchannel_key(&selx, &sel, &conchan);
415
416         if (chan){
417                 if (selectmode == SELECT_REPLACE) {
418                         if (sel == 0)
419                                 selectmode = SELECT_ADD;
420                         else
421                                 selectmode = SELECT_SUBTRACT;
422                         deselect_actionchannel_keys(act, 0);
423                         deselect_actionchannels(act, 0);
424                         act->achan = chan;
425                         chan->flag |= ACHAN_SELECTED;
426                         hilight_channel (act, chan, 1);
427                 }
428                 
429                 if (conchan)
430                         select_ipo_key(conchan->ipo, selx, selectmode);
431                 else
432                         select_ipo_key(chan->ipo, selx, selectmode);
433
434                 allqueue(REDRAWIPO, 0);
435                 allqueue(REDRAWVIEW3D, 0);
436                 allqueue(REDRAWACTION, 0);
437                 allqueue(REDRAWNLA, 0);
438
439         }
440 }
441
442 static void borderselect_action(void)
443
444         rcti rect;
445         rctf rectf;
446         int val, selectmode;            
447         short   mval[2];
448         bActionChannel *chan;
449         bConstraintChannel *conchan;
450         bAction *act;
451         float   ymin, ymax;
452
453         act=G.saction->action;
454
455
456         if (!act)
457                 return;
458
459         if ( (val = get_border(&rect, 3)) ){
460     if (val == LEFTMOUSE)
461       selectmode = SELECT_ADD;
462     else
463       selectmode = SELECT_SUBTRACT;
464
465                 mval[0]= rect.xmin;
466                 mval[1]= rect.ymin+2;
467                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
468                 mval[0]= rect.xmax;
469                 mval[1]= rect.ymax-2;
470                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
471                 
472                 ymax=count_action_levels(act) * (CHANNELHEIGHT+CHANNELSKIP);
473                 for (chan=act->chanbase.first; chan; chan=chan->next){
474                         
475                         /* Check action */
476                         ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
477                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
478           borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax,
479                                selectmode);
480
481                         ymax=ymin;
482
483                         /* Check constraints */
484                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
485                                 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
486                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
487                                         borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
488                                selectmode);
489                                 
490                                 ymax=ymin;
491                         }
492                 }       
493                 allqueue(REDRAWNLA, 0);
494                 allqueue(REDRAWACTION, 0);
495                 allqueue(REDRAWIPO, 0);
496         }
497 }
498
499 bActionChannel* get_hilighted_action_channel(bAction* action)
500 {
501         bActionChannel *chan;
502
503         if (!action)
504                 return NULL;
505
506         for (chan=action->chanbase.first; chan; chan=chan->next){
507                 if (chan->flag & ACHAN_SELECTED && chan->flag & ACHAN_HILIGHTED)
508                         return chan;
509         }
510
511         return NULL;
512
513 }
514
515 void set_exprap_action(int mode)
516 {
517         if(G.saction->action && G.saction->action->id.lib) return;
518
519         error ("Not yet implemented!");
520 }
521
522 void free_posebuf(void) 
523 {
524         if (g_posebuf){
525                 clear_pose(g_posebuf);
526                 MEM_freeN (g_posebuf);
527         }
528         g_posebuf=NULL;
529 }
530
531 void copy_posebuf (void)
532 {
533         Object *ob;
534
535         free_posebuf();
536
537         ob=G.obpose;
538         if (!ob){
539                 error ("Copybuf is empty");
540                 return;
541         }
542
543         filter_pose_keys();
544         copy_pose(&g_posebuf, ob->pose, 0);
545
546 }
547
548 static void flip_name (char *name)
549 {
550
551         char    prefix[128]={""};       /* The part before the facing */
552         char    suffix[128]={""};       /* The part after the facing */
553         char    replace[128]={""};      /* The replacement string */
554
555         char    *index=NULL;
556         /* Find the last period */
557
558         strcpy (prefix, name);
559
560         /* Check for an instance of .Right */
561         if (!index){
562                 index = strstr (prefix, "Right");
563                 if (index){
564                         *index=0;
565                         strcpy (replace, "Left");
566                         strcpy (suffix, index+6);
567                 }
568         }
569
570         /* Che ck for an instance of .RIGHT */
571         if (!index){
572                 index = strstr (prefix, "RIGHT");
573                 if (index){
574                         *index=0;
575                         strcpy (replace, "LEFT");
576                         strcpy (suffix, index+6);
577                 }
578         }
579
580
581         /* Check for an instance of .right */
582         if (!index){
583                 index = strstr (prefix, "right");
584                 if (index){
585                         *index=0;
586                         strcpy (replace, "left");
587                         strcpy (suffix, index+6);
588                 }
589         }
590
591         /* Check for an instance of .left */
592         if (!index){
593                 index = strstr (prefix, "left");
594                 if (index){
595                         *index=0;
596                         strcpy (replace, "right");
597                         strcpy (suffix, index+5);
598                 }
599         }
600
601         /* Check for an instance of .LEFT */
602         if (!index){
603                 index = strstr (prefix, "LEFT");
604                 if (index){
605                         *index=0;
606                         strcpy (replace, "RIGHT");
607                         strcpy (suffix, index+5);
608                 }
609         }
610
611         /* Check for an instance of .Left */
612         if (!index){
613                 index = strstr (prefix, "Left");
614                 if (index){
615                         *index=0;
616                         strcpy (replace, "Right");
617                         strcpy (suffix, index+5);
618                 }
619         }
620
621         /* check for an instance of .L */
622         if (!index){
623                 index = strstr (prefix, ".L");
624                 if (index){
625                         *index=0;
626                         strcpy (replace, ".R");
627                         strcpy (suffix, index+2);
628                 }
629         }
630
631         /* check for an instance of .l */
632         if (!index){
633                 index = strstr (prefix, ".l");
634                 if (index){
635                         *index=0;
636                         strcpy (replace, ".r");
637                         strcpy (suffix, index+2);
638                 }
639         }
640
641         /* Checl for an instance of .R */
642         if (!index){
643                 index = strstr (prefix, ".R");
644                 if (index){
645                         *index=0;
646                         strcpy (replace, ".L");
647                         strcpy (suffix, index+2);
648                 }
649         }
650
651         /* Checl for an instance of .r */
652         if (!index){
653                 index = strstr (prefix, ".r");
654                 if (index){
655                         *index=0;
656                         strcpy (replace, ".l");
657                         strcpy (suffix, index+2);
658                 }
659         }
660
661         sprintf (name, "%s%s%s", prefix, replace, suffix);
662 }
663
664 void paste_posebuf (int flip){
665         Object *ob;
666         bPoseChannel *temp, *chan;
667         float eul[4];
668         Base    *base;
669         int             newchan = 0;
670
671         ob=G.obpose;
672         if (!ob)
673                 return;
674
675         if (!g_posebuf){
676                 error ("Copybuf is empty");
677                 return;
678         };
679         
680         collect_pose_garbage(ob);
681
682         /* Safely merge all of the channels in this pose into
683         any existing pose */
684         if (ob->pose){
685                 if (U.uiflag & KEYINSERTACT){
686                         /* Display "Avail, all" dialog */
687                 }
688                 for (chan=g_posebuf->chanbase.first; chan; chan=chan->next){
689                         if (chan->flag & POSE_KEY){
690                                 temp = copy_pose_channel (chan);
691                                 if (flip){
692                                         flip_name (temp->name);
693                                         temp->loc[0]*=-1;
694
695                                         QuatToEul(temp->quat, eul);
696                                         eul[1]*=-1;
697                                         eul[2]*=-1;
698                                         EulToQuat(eul, temp->quat);
699                                 }
700
701                                 temp = set_pose_channel (ob->pose, temp);
702
703                                 if (U.uiflag & KEYINSERTACT){
704                                         /* Set keys on pose */
705                                         if (chan->flag & POSE_ROT){
706                                                 set_action_key(ob->action, temp, AC_QUAT_X, newchan);
707                                                 set_action_key(ob->action, temp, AC_QUAT_Y, newchan);
708                                                 set_action_key(ob->action, temp, AC_QUAT_Z, newchan);
709                                                 set_action_key(ob->action, temp, AC_QUAT_W, newchan);
710                                         };
711                                         if (chan->flag & POSE_SIZE){
712                                                 set_action_key(ob->action, temp, AC_SIZE_X, newchan);
713                                                 set_action_key(ob->action, temp, AC_SIZE_Y, newchan);
714                                                 set_action_key(ob->action, temp, AC_SIZE_Z, newchan);
715                                         };
716                                         if (chan->flag & POSE_LOC){
717                                                 set_action_key(ob->action, temp, AC_LOC_X, newchan);
718                                                 set_action_key(ob->action, temp, AC_LOC_Y, newchan);
719                                                 set_action_key(ob->action, temp, AC_LOC_Z, newchan);
720                                         };                                      
721                                 }
722                         }
723                 }
724
725                 if (U.uiflag & KEYINSERTACT){
726                         remake_action_ipos(ob->action);
727                         allqueue (REDRAWIPO, 0);
728                         allqueue (REDRAWVIEW3D, 0);
729                         allqueue (REDRAWACTION, 0);             
730                         allqueue(REDRAWNLA, 0);
731                 }
732
733                 /* Update deformation children */
734                 if (G.obpose->type == OB_ARMATURE){
735                         for (base= FIRSTBASE; base; base= base->next){
736                                 if (G.obpose==base->object->parent){
737                                         if (base->object->partype==PARSKEL)
738                                                 makeDispList(base->object);
739                                 }
740                         }
741                 }
742         }
743 }
744
745 void set_action_key (struct bAction *act, struct bPoseChannel *chan, int adrcode, short makecurve)
746 {
747         set_action_key_time (act, chan, adrcode, makecurve, frame_to_float(CFRA));
748 }
749
750 static void set_action_key_time (bAction *act, bPoseChannel *chan, int adrcode, short makecurve, float time)
751 {
752         bActionChannel  *achan;
753         char    ipstr[256];
754
755         if (!act)
756                 return;
757
758         if (!chan)
759                 return;
760         /* See if this action channel exists already */ 
761         for (achan=act->chanbase.first; achan; achan=achan->next){
762                 if (!strcmp (chan->name, achan->name))
763                         break;
764         }
765
766         if (!achan){
767                 if (!makecurve)
768                         return;
769                 achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
770                 strcpy (achan->name, chan->name);
771                 BLI_addtail (&act->chanbase, achan);
772         }
773
774         /* Ensure the channel appears selected in the action window */
775         achan->flag |= ACHAN_SELECTED;
776
777         /* Ensure this action channel has a valid Ipo */
778         if (!achan->ipo){
779                 sprintf (ipstr, "%s.%s", act->id.name+2, chan->name);
780                 ipstr[23]=0;
781                 achan->ipo=     add_ipo(ipstr, ID_AC);  
782         }
783
784         insertactionkey(act, achan, chan, adrcode, makecurve, time);
785
786 }
787
788 static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float cfra)
789 {
790         IpoCurve *icu;
791         void *poin;
792         float curval;
793         int type;
794         ID *id;
795         
796         if (!act){
797                 return;
798         }
799         if (act->id.lib){
800                 error ("Can't pose libactions");
801                 return;
802         }
803         act->achan=achan;
804         act->pchan=chan;
805
806         id=(ID*) act;
807
808         /* First see if this curve exists */
809         if (!makecurve){
810                 if (!achan->ipo)
811                         return;
812
813                 for (icu = achan->ipo->curve.first; icu; icu=icu->next){
814                         if (icu->adrcode == adrcode)
815                                 break;
816                 }
817                 if (!icu)
818                         return;
819         }
820
821         
822         icu = get_ipocurve (id, GS(id->name), adrcode, achan->ipo);
823
824         if(icu) {
825                 poin= get_ipo_poin(id, icu, &type);
826                 if(poin) {
827                         curval= read_ipo_poin(poin, type);
828         //              cfra= frame_to_float(CFRA);
829                         insert_vert_ipo(icu, cfra, curval);
830                 }
831         }
832         
833 }
834
835 bAction *add_empty_action(void)
836 {
837         bAction *act;
838
839         act= alloc_libblock(&G.main->action, ID_AC, "Action");
840         act->id.flag |= LIB_FAKEUSER;
841         act->id.us++;
842         return act;
843 }
844
845 static void transform_actionchannel_keys(char mode)
846 {
847         bAction *act;
848         TransVert *tv;
849         int /*sel=0,*/  i;
850         bActionChannel  *chan;
851         short   mvals[2], mvalc[2], cent[2];
852         float   sval[2], cval[2], lastcval[2];
853         short   cancel=0;
854         float   fac=0.0F;
855         int             loop=1;
856         int             tvtot=0;
857         float   deltax, startx;
858         float   cenf[2];
859         int             invert=0, firsttime=1;
860         char    str[256];
861         bConstraintChannel *conchan;
862
863         act=G.saction->action;
864
865         /* Ensure that partial selections result in beztriple selections */
866         for (chan=act->chanbase.first; chan; chan=chan->next){
867                 tvtot+=fullselect_ipo_keys(chan->ipo);
868
869                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
870                         tvtot+=fullselect_ipo_keys(conchan->ipo);
871         }
872         
873         /* If nothing is selected, bail out */
874         if (!tvtot)
875                 return;
876         
877         
878         /* Build the transvert structure */
879         tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
880         tvtot=0;
881         for (chan=act->chanbase.first; chan; chan=chan->next){
882                 /* Add the actionchannel */
883                 tvtot = add_trans_ipo_keys(chan->ipo, tv, tvtot);
884                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
885                         tvtot = add_trans_ipo_keys(conchan->ipo, tv, tvtot);
886         }
887
888         /* Do the event loop */
889         cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2;
890         cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2;
891         areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]);
892
893         getmouseco_areawin (mvals);
894         areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
895
896         startx=sval[0];
897         while (loop) {
898                 /*              Get the input */
899                 /*              If we're cancelling, reset transformations */
900                 /*                      Else calc new transformation */
901                 /*              Perform the transformations */
902                 while (qtest()) {
903                         short val;
904                         unsigned short event= extern_qread(&val);
905
906                         if (val) {
907                                 switch (event) {
908                                 case LEFTMOUSE:
909                                 case SPACEKEY:
910                                 case RETKEY:
911                                         loop=0;
912                                         break;
913                                 case XKEY:
914                                         break;
915                                 case ESCKEY:
916                                 case RIGHTMOUSE:
917                                         cancel=1;
918                                         loop=0;
919                                         break;
920                                 default:
921                                         arrows_move_cursor(event);
922                                         break;
923                                 };
924                         }
925                 }
926
927                 if (cancel) {
928                         for (i=0; i<tvtot; i++) {
929                                 tv[i].loc[0]=tv[i].oldloc[0];
930                                 tv[i].loc[1]=tv[i].oldloc[1];
931                         }
932                 } else {
933                         getmouseco_areawin (mvalc);
934                         areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
935
936                         if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
937                                 PIL_sleep_ms(1);
938                         } else {
939                                 for (i=0; i<tvtot; i++){
940                                         tv[i].loc[0]=tv[i].oldloc[0];
941
942                                         switch (mode){
943                                         case 'g':
944                                                 deltax = cval[0]-sval[0];
945                                                 fac= deltax;
946                                                 
947                                                 apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & AUTOGRABGRID);
948
949                                                 tv[i].loc[0]+=fac;
950                                                 break;
951                                         case 's':
952                                                 startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
953                                                 deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
954                                                 fac= fabs(deltax/startx);
955                                                 
956                                                 apply_keyb_grid(&fac, 0.0, 0.2, 0.1, U.flag & AUTOSIZEGRID);
957                 
958                                                 if (invert){
959                                                         if (i % 03 == 0){
960                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
961                                                         }
962                                                         if (i % 03 == 2){
963                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
964                                                         }
965         
966                                                         fac*=-1;
967                                                 }
968                                                 startx= (G.scene->r.cfra);
969                                         
970                                                 tv[i].loc[0]-= startx;
971                                                 tv[i].loc[0]*=fac;
972                                                 tv[i].loc[0]+= startx;
973                 
974                                                 break;
975                                         }
976                                 }
977                         }
978         
979                         if (mode=='s'){
980                                 sprintf(str, "sizeX: %.3f", fac);
981                                 headerprint(str);
982                         }
983                         else if (mode=='g'){
984                                 sprintf(str, "deltaX: %.3f", fac);
985                                 headerprint(str);
986                         }
987         
988                         if (G.saction->lock){
989                                 do_all_actions();
990                                 allqueue (REDRAWVIEW3D, 0);
991                                 allqueue (REDRAWACTION, 0);
992                                 allqueue (REDRAWIPO, 0);
993                                 allqueue(REDRAWNLA, 0);
994                                 force_draw_all();
995                         }
996                         else {
997                                 addqueue (curarea->win, REDRAWALL, 0);
998                                 force_draw ();
999                         }
1000                 }
1001                 
1002                 lastcval[0]= cval[0];
1003                 lastcval[1]= cval[1];
1004                 firsttime= 0;
1005         }
1006         
1007         /*              Update the curve */
1008         /*              Depending on the lock status, draw necessary views */
1009
1010         do_all_actions();
1011         remake_action_ipos(act);
1012         allqueue (REDRAWVIEW3D, 0);
1013         allqueue (REDRAWACTION, 0);
1014         allqueue(REDRAWNLA, 0);
1015         allqueue (REDRAWIPO, 0);
1016         MEM_freeN (tv);
1017 }
1018
1019 void deselect_actionchannel_keys (bAction *act, int test)
1020 {
1021         bActionChannel  *chan;
1022         bConstraintChannel *conchan;
1023         int             sel=1;;
1024
1025         if (!act)
1026                 return;
1027
1028         /* Determine if this is selection or deselection */
1029         
1030         if (test){
1031                 for (chan=act->chanbase.first; chan; chan=chan->next){
1032                         /* Test the channel ipos */
1033                         if (is_ipo_key_selected(chan->ipo)){
1034                                 sel = 0;
1035                                 break;
1036                         }
1037
1038                         /* Test the constraint ipos */
1039                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1040                                 if (is_ipo_key_selected(conchan->ipo)){
1041                                         sel = 0;
1042                                         break;
1043                                 }
1044                         }
1045
1046                         if (sel == 0)
1047                                 break;
1048                 }
1049         }
1050         else
1051                 sel=0;
1052         
1053         /* Set the flags */
1054         for (chan=act->chanbase.first; chan; chan=chan->next){
1055                 set_ipo_key_selection(chan->ipo, sel);
1056                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1057                         set_ipo_key_selection(conchan->ipo, sel);
1058         }
1059 }
1060
1061 void deselect_actionchannels (bAction *act, int test)
1062 {
1063         bActionChannel *chan;
1064         bConstraintChannel *conchan;
1065         int                     sel=1;  
1066
1067         if (!act)
1068                 return;
1069
1070         /* See if we should be selecting or deselecting */
1071         if (test){
1072                 for (chan=act->chanbase.first; chan; chan=chan->next){
1073                         if (!sel)
1074                                 break;
1075
1076                         if (chan->flag & ACHAN_SELECTED){
1077                                 sel=0;
1078                                 break;
1079                         }
1080                         if (sel){
1081                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1082                                         if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1083                                                 sel=0;
1084                                                 break;
1085                                         }
1086                                 }
1087                         }
1088                 }
1089         }
1090         else
1091                 sel=0;
1092
1093         /* Now set the flags */
1094         for (chan=act->chanbase.first; chan; chan=chan->next){
1095                 select_poseelement_by_name(chan->name, sel);
1096
1097                 if (sel)
1098                         chan->flag |= ACHAN_SELECTED;
1099                 else
1100                         chan->flag &= ~ACHAN_SELECTED;
1101
1102                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1103                         if (sel)
1104                                 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1105                         else
1106                                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1107                 }
1108         }
1109
1110 }
1111
1112 static void hilight_channel (bAction *act, bActionChannel *chan, short select)
1113 {
1114         bActionChannel *curchan;
1115
1116         if (!act)
1117                 return;
1118
1119         for (curchan=act->chanbase.first; curchan; curchan=curchan->next){
1120                 if (curchan==chan && select)
1121                         curchan->flag |= ACHAN_HILIGHTED;
1122                 else
1123                         curchan->flag &= ~ACHAN_HILIGHTED;
1124         }
1125 }
1126
1127 static int select_channel(bAction *act, bActionChannel *chan,
1128                           int selectmode) {
1129         /* Select the channel based on the selection mode
1130          */
1131         int flag;
1132
1133         switch (selectmode) {
1134         case SELECT_ADD:
1135                 chan->flag |= ACHAN_SELECTED;
1136                 break;
1137         case SELECT_SUBTRACT:
1138                 chan->flag &= ~ACHAN_SELECTED;
1139                 break;
1140         case SELECT_INVERT:
1141                 chan->flag ^= ACHAN_SELECTED;
1142                 break;
1143         }
1144         flag = (chan->flag & ACHAN_SELECTED) ? 1 : 0;
1145
1146         hilight_channel(act, chan, flag);
1147         select_poseelement_by_name(chan->name, flag);
1148
1149         return flag;
1150 }
1151
1152 static int select_constraint_channel(bAction *act, 
1153                                      bConstraintChannel *conchan, 
1154                                      int selectmode) {
1155         /* Select the constraint channel based on the selection mode
1156          */
1157         int flag;
1158
1159         switch (selectmode) {
1160         case SELECT_ADD:
1161                 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1162                 break;
1163         case SELECT_SUBTRACT:
1164                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1165                 break;
1166         case SELECT_INVERT:
1167                 conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
1168                 break;
1169         }
1170         flag = (conchan->flag & CONSTRAINT_CHANNEL_SELECT) ? 1 : 0;
1171
1172         return flag;
1173 }
1174
1175
1176 static void mouse_actionchannels(bAction *act, short *mval,
1177                                  short *mvalo, int selectmode) {
1178         /* Select action channels, based on mouse values.
1179          * If mvalo is NULL we assume it is a one click
1180          * action, other wise we treat it like it is a
1181          * border select with mval[0],mval[1] and
1182          * mvalo[0], mvalo[1] forming the corners of
1183          * a rectangle.
1184          */
1185         bActionChannel *chan;
1186         float   click;
1187         int   clickmin, clickmax;
1188         int             wsize, sel;
1189         bConstraintChannel *conchan;
1190
1191         if (!act)
1192                 return;
1193   
1194         if (selectmode == SELECT_REPLACE) {
1195                 deselect_actionchannels (act, 0);
1196                 selectmode = SELECT_ADD;
1197         }
1198
1199         /* wsize is the greatest possible height (in pixels) that would be
1200          * needed to draw all of the action channels and constraint
1201          * channels.
1202          */
1203         wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP));
1204
1205         click = (wsize-(mval[1]+G.v2d->cur.ymin));
1206         click += CHANNELHEIGHT/2;
1207         click /= (CHANNELHEIGHT+CHANNELSKIP);
1208         
1209         clickmin = (int) click;
1210
1211         /* Only one click */
1212         if (mvalo == NULL) {
1213                 clickmax = clickmin;
1214         }
1215         /* Two click values (i.e., border select */
1216         else {
1217                 click = (wsize-(mvalo[1]+G.v2d->cur.ymin));
1218                 click += CHANNELHEIGHT/2;
1219                 click /= (CHANNELHEIGHT+CHANNELSKIP);
1220
1221                 if ( ((int) click) < clickmin) {
1222                         clickmax = clickmin;
1223                         clickmin = (int) click;
1224                 }
1225                 else {
1226                         clickmax = (int) click;
1227                 }
1228         }
1229
1230         if (clickmax < 0) {
1231                 return;
1232         }
1233
1234         /* clickmin and clickmax now coorespond to indices into
1235          * the collection of channels and constraint channels.
1236          * What we need to do is apply the selection mode on all
1237          * channels and constraint channels between these indices.
1238          * This is done by traversing the channels and constraint
1239          * channels, for each item decrementing clickmin and clickmax.
1240          * When clickmin is less than zero we start selecting stuff,
1241          * until clickmax is less than zero or we run out of channels
1242          * and constraint channels.
1243          */
1244
1245         for (chan = act->chanbase.first; chan; chan=chan->next){
1246                 if (clickmax < 0) break;
1247
1248                 if ( clickmin <= 0) {
1249                         /* Select the channel with the given mode. If the
1250                          * channel is freshly selected then set it to the
1251                          * active channel for the action
1252                          */
1253                         sel = (chan->flag & ACHAN_SELECTED);
1254                         if ( select_channel(act, chan, selectmode) && !sel ) {
1255                                 act->achan = chan;
1256                         }
1257                 }
1258                 --clickmin;
1259                 --clickmax;
1260
1261                 /* Check for click in a constraint */
1262                 for (conchan=chan->constraintChannels.first; 
1263                          conchan; conchan=conchan->next){
1264                         if (clickmax < 0) break;
1265                         if ( clickmin <= 0) {
1266                                 select_constraint_channel(act, conchan, selectmode);
1267                         }
1268                         --clickmin;
1269                         --clickmax;
1270                 }
1271         }
1272
1273         allqueue (REDRAWIPO, 0);
1274         allqueue (REDRAWVIEW3D, 0);
1275         allqueue (REDRAWACTION, 0);
1276         allqueue (REDRAWNLA, 0);
1277 }
1278
1279
1280 static void delete_actionchannel_keys(void)
1281 {
1282         bAction *act;
1283         bActionChannel *chan;
1284         bConstraintChannel *conchan;
1285
1286         act = G.saction->action;
1287         if (!act)
1288                 return;
1289
1290         if (!okee("Erase selected keys"))
1291                 return;
1292
1293         for (chan = act->chanbase.first; chan; chan=chan->next){
1294
1295                 /* Check action channel keys*/
1296                 delete_ipo_keys(chan->ipo);
1297
1298                 /* Delete constraint channel keys */
1299                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1300                         delete_ipo_keys(conchan->ipo);
1301         }
1302
1303         remake_action_ipos (act);
1304         allspace(REMAKEIPO, 0);
1305         allqueue(REDRAWACTION, 0);
1306         allqueue(REDRAWIPO, 0);
1307         allqueue(REDRAWNLA, 0);
1308
1309 }
1310 static void delete_actionchannels (void)
1311 {
1312         bConstraintChannel *conchan, *nextconchan;
1313         bActionChannel *chan, *next;
1314         bAction *act;
1315         int freechan;
1316
1317         act=G.saction->action;
1318
1319         if (!act)
1320                 return;
1321
1322         for (chan=act->chanbase.first; chan; chan=chan->next){
1323                 if (chan->flag & ACHAN_SELECTED)
1324                         break;
1325                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1326                 {
1327                         if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1328                                 chan=act->chanbase.last;
1329                                 break;
1330                         }
1331                 }
1332         }
1333
1334         if (!chan && !conchan)
1335                 return;
1336
1337         if (!okee("Erase selected channels"))
1338                 return;
1339
1340         for (chan=act->chanbase.first; chan; chan=next){
1341                 freechan = 0;
1342                 next=chan->next;
1343                 
1344                 /* Remove action channels */
1345                 if (chan->flag & ACHAN_SELECTED){
1346                         if (chan->ipo)
1347                                 chan->ipo->id.us--;     /* Release the ipo */
1348                         freechan = 1;
1349                 }
1350                 
1351                 /* Remove constraint channels */
1352                 for (conchan=chan->constraintChannels.first; conchan; conchan=nextconchan){
1353                         nextconchan=conchan->next;
1354                         if (freechan || conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1355                                 if (conchan->ipo)
1356                                         conchan->ipo->id.us--;
1357                                 BLI_freelinkN(&chan->constraintChannels, conchan);
1358                         }
1359                 }
1360                 
1361                 if (freechan)
1362                         BLI_freelinkN (&act->chanbase, chan);
1363
1364         }
1365
1366         allqueue (REDRAWACTION, 0);
1367         allqueue(REDRAWNLA, 0);
1368
1369 }
1370
1371 static void sethandles_actionchannel_keys(int code)
1372 {
1373         bAction *act;
1374         bActionChannel *chan;
1375
1376         /* Get the selected action, exit if none are selected 
1377          */
1378         act = G.saction->action;
1379         if (!act)
1380                 return;
1381
1382         /* Loop through the channels and set the beziers
1383          * of the selected keys based on the integer code
1384          */
1385         for (chan = act->chanbase.first; chan; chan=chan->next){
1386                 sethandles_ipo_keys(chan->ipo, code);
1387         }
1388
1389         /* Clean up and redraw stuff
1390          */
1391         remake_action_ipos (act);
1392         allspace(REMAKEIPO, 0);
1393         allqueue(REDRAWACTION, 0);
1394         allqueue(REDRAWIPO, 0);
1395         allqueue(REDRAWNLA, 0);
1396 }
1397
1398 static void set_ipotype_actionchannels(void) {
1399
1400         bAction *act; 
1401         bActionChannel *chan;
1402         short event;
1403
1404         /* Get the selected action, exit if none are selected 
1405          */
1406         act = G.saction->action;
1407         if (!act)
1408                 return;
1409
1410         /* Present a popup menu asking the user what type
1411          * of IPO curve he/she/GreenBTH wants. ;)
1412          */
1413         event= pupmenu("Channel Ipo Type %t|Constant %x1|Linear %x2|Bezier %x3");
1414         if(event < 1) return;
1415         
1416         /* Loop through the channels and for the selected ones set
1417          * the type for each Ipo curve in the channel Ipo (based on
1418          * the value from the popup).
1419          */
1420         for (chan = act->chanbase.first; chan; chan=chan->next){
1421                 if (chan->flag & ACHAN_SELECTED){
1422                         if (chan->ipo)
1423                                 setipotype_ipo(chan->ipo, event);
1424                 }
1425         }
1426
1427         /* Clean up and redraw stuff
1428          */
1429         remake_action_ipos (act);
1430         allspace(REMAKEIPO, 0);
1431         allqueue(REDRAWACTION, 0);
1432         allqueue(REDRAWIPO, 0);
1433         allqueue(REDRAWNLA, 0);
1434 }
1435
1436 void select_all_keys_frames(bAction *act, short *mval, 
1437                                                         short *mvalo, int selectmode) {
1438         
1439         /* This function tries to select all action keys in
1440          * every channel for a given range of keyframes that
1441          * are within the mouse values mval and mvalo (usually
1442          * the result of a border select). If mvalo is passed as
1443          * NULL then the selection is treated as a one-click and
1444          * the function tries to select all keys within half a
1445          * frame of the click point.
1446          */
1447         
1448         rcti rect;
1449         rctf rectf;
1450         bActionChannel *chan;
1451         bConstraintChannel *conchan;
1452
1453         if (!act)
1454                 return;
1455
1456         if (selectmode == SELECT_REPLACE) {
1457                 deselect_actionchannel_keys(act, 0);
1458                 selectmode = SELECT_ADD;
1459         }
1460
1461         if (mvalo == NULL) {
1462                 rect.xmin = rect.xmax = mval[0];
1463                 rect.ymin = rect.ymax = mval[1];
1464         }
1465         else {
1466                 if (mval[0] < mvalo[0] ) {
1467                         rect.xmin = mval[0];
1468                         rect.xmax = mvalo[0];
1469                 }
1470                 else {
1471                         rect.xmin = mvalo[0];
1472                         rect.xmax = mval[0];
1473                 }
1474                 if (mval[1] < mvalo[1] ) {
1475                         rect.ymin = mval[1];
1476                         rect.ymax = mvalo[1];
1477                 }
1478                 else {
1479                         rect.ymin = mvalo[1];
1480                         rect.ymax = mval[1];
1481                 }
1482         }
1483
1484         mval[0]= rect.xmin;
1485         mval[1]= rect.ymin+2;
1486         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1487         mval[0]= rect.xmax;
1488         mval[1]= rect.ymax-2;
1489         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1490
1491         if (mvalo == NULL) {
1492                 rectf.xmin = rectf.xmin - 0.5;
1493                 rectf.xmax = rectf.xmax + 0.5;
1494         }
1495     
1496         for (chan=act->chanbase.first; chan; chan=chan->next){
1497                 borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax,
1498                                                          selectmode);
1499                 for (conchan=chan->constraintChannels.first; conchan; 
1500                          conchan=conchan->next){
1501                         borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
1502                                                                  selectmode);
1503                 }
1504         }       
1505         allqueue(REDRAWNLA, 0);
1506         allqueue(REDRAWACTION, 0);
1507         allqueue(REDRAWIPO, 0);
1508 }
1509
1510
1511 void select_all_keys_channels(bAction *act, short *mval, 
1512                               short *mvalo, int selectmode) {
1513         bActionChannel    *chan;
1514         float              click;
1515         int                clickmin, clickmax;
1516         int                wsize;
1517         bConstraintChannel *conchan;
1518
1519         /* This function selects all the action keys that
1520          * are in the mouse selection range defined by
1521          * the ordered pairs mval and mvalo (usually
1522          * these 2 are obtained from a border select).
1523          * If mvalo is NULL, then the selection is
1524          * treated like a one-click action, and at most
1525          * one channel is selected.
1526          */
1527
1528         /* If the action is null then abort
1529          */
1530         if (!act)
1531                 return;
1532
1533         if (selectmode == SELECT_REPLACE) {
1534                 deselect_actionchannel_keys(act, 0);
1535                 selectmode = SELECT_ADD;
1536         }
1537
1538         /* wsize is the greatest possible height (in pixels) that would be
1539          * needed to draw all of the action channels and constraint
1540          * channels.
1541          */
1542         wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP));
1543
1544         click = (wsize-(mval[1]+G.v2d->cur.ymin));
1545         click += CHANNELHEIGHT/2;
1546         click /= (CHANNELHEIGHT+CHANNELSKIP);
1547
1548         clickmin = (int) click;
1549
1550         /* Only one click */
1551         if (mvalo == NULL) {
1552                 clickmax = clickmin;
1553         }
1554         /* Two click values (i.e., border select) */
1555         else {
1556                 click = (wsize-(mvalo[1]+G.v2d->cur.ymin));
1557                 click += CHANNELHEIGHT/2;
1558                 click /= (CHANNELHEIGHT+CHANNELSKIP);
1559
1560                 if ( ((int) click) < clickmin) {
1561                         clickmax = clickmin;
1562                         clickmin = (int) click;
1563                 }
1564                 else {
1565                         clickmax = (int) click;
1566                 }
1567         }
1568
1569         if (clickmax < 0) {
1570                 return;
1571         }
1572
1573         for (chan = act->chanbase.first; chan; chan=chan->next){
1574                 if (clickmax < 0) break;
1575
1576                 if ( clickmin <= 0) {
1577                         /* Select the channel with the given mode. If the
1578                          * channel is freshly selected then set it to the
1579                          * active channel for the action
1580                          */
1581                         select_ipo_bezier_keys(chan->ipo, selectmode);
1582                 }
1583                 --clickmin;
1584                 --clickmax;
1585
1586                 /* Check for click in a constraint */
1587                 for (conchan=chan->constraintChannels.first; 
1588                          conchan; conchan=conchan->next){
1589                         if (clickmax < 0) break;
1590                         if ( clickmin <= 0) {
1591                                 select_ipo_bezier_keys(chan->ipo, selectmode);
1592                         }
1593                         --clickmin;
1594                         --clickmax;
1595                 }
1596         }
1597   
1598         allqueue (REDRAWIPO, 0);
1599         allqueue (REDRAWVIEW3D, 0);
1600         allqueue (REDRAWACTION, 0);
1601         allqueue (REDRAWNLA, 0);
1602   
1603 }
1604
1605 static void borderselect_function(void (*select_func)(bAction *act, 
1606                                                      short *mval, 
1607                                                      short *mvalo, 
1608                                                      int selectmode)) {
1609         /* This function executes an arbitrary selection
1610          * function as part of a border select. This
1611          * way the same function that is used for
1612          * right click selection points can generally
1613          * be used as the argument to this function
1614          */
1615         rcti rect;
1616         short   mval[2], mvalo[2];
1617         bAction *act;
1618         int val;                
1619
1620         /* Get the selected action, exit if none are selected 
1621          */
1622         act=G.saction->action;
1623         if (!act)
1624                 return;
1625
1626         /* Let the user draw a border (or abort)
1627          */
1628         if ( (val=get_border (&rect, 3)) ) {
1629                 mval[0]= rect.xmin;
1630                 mval[1]= rect.ymin+2;
1631                 mvalo[0]= rect.xmax;
1632                 mvalo[1]= rect.ymax-2;
1633
1634                 /* if the left mouse was used, do an additive
1635                  * selection with the user defined selection
1636                  * function.
1637                  */
1638                 if (val == LEFTMOUSE)
1639                         select_func(act, mval, mvalo, SELECT_ADD);
1640                 
1641                 /* if the right mouse was used, do a subtractive
1642                  * selection with the user defined selection
1643                  * function.
1644                  */
1645                 else if (val == RIGHTMOUSE)
1646                         select_func(act, mval, mvalo, SELECT_SUBTRACT);
1647         }
1648         
1649 }
1650
1651 void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1652 {
1653         unsigned short event= evt->event;
1654         short val= evt->val;
1655         char ascii= evt->ascii;
1656         SpaceAction *saction;
1657         bAction *act;
1658         int doredraw= 0;
1659         short   mval[2];
1660         float dx,dy;
1661         int     cfra;
1662         
1663         if(curarea->win==0) return;
1664
1665         saction= curarea->spacedata.first;
1666         if (!saction)
1667                 return;
1668
1669         act=saction->action;
1670         if(val) {
1671                 
1672                 if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
1673                 
1674                 getmouseco_areawin(mval);
1675
1676                 switch(event) {
1677                 case UI_BUT_EVENT:
1678                         do_blenderbuttons(val);
1679                         break;
1680                 case HOMEKEY:
1681                         do_action_buttons(B_ACTHOME);
1682                         break;
1683
1684                 case CKEY:
1685                         /* scroll the window so the current
1686                          * frame is in the center.
1687                          */
1688                         center_currframe();
1689                         break;
1690
1691                 case DKEY:
1692                         if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH){
1693                                 duplicate_actionchannel_keys();
1694                                 remake_action_ipos(act);
1695                         }
1696                         break;
1697                 case DELKEY:
1698                 case XKEY:
1699                         if (mval[0]<ACTWIDTH)
1700                                 delete_actionchannels ();
1701                         else
1702                                 delete_actionchannel_keys ();
1703                         break;
1704                 case GKEY:
1705                         if (mval[0]>=ACTWIDTH)
1706                                 transform_actionchannel_keys ('g');
1707                         break;
1708                 case SKEY:
1709                         if (mval[0]>=ACTWIDTH)
1710                                 transform_actionchannel_keys ('s');
1711                         break;
1712                 case AKEY:
1713                         if (mval[0]<ACTWIDTH){
1714                                 deselect_actionchannels (act, 1);
1715                                 allqueue (REDRAWVIEW3D, 0);
1716                                 allqueue (REDRAWACTION, 0);
1717                                 allqueue(REDRAWNLA, 0);
1718                                 allqueue (REDRAWIPO, 0);
1719                         }
1720                         else{
1721                                 deselect_actionchannel_keys (act, 1);
1722                                 allqueue (REDRAWACTION, 0);
1723                                 allqueue(REDRAWNLA, 0);
1724                                 allqueue (REDRAWIPO, 0);
1725                         }
1726                         break;
1727
1728                         /*** set the Ipo handles ***/
1729                 case VKEY:
1730                         sethandles_actionchannel_keys(HD_VECT);
1731                         break;
1732                 case HKEY:
1733                         if(G.qual & LR_SHIFTKEY) sethandles_actionchannel_keys(HD_AUTO);
1734                         else sethandles_actionchannel_keys(HD_ALIGN);
1735                         break;
1736  
1737                         /*** set the Ipo type  ***/
1738                 case TKEY:
1739                         set_ipotype_actionchannels();
1740                         break;
1741
1742                 case BKEY:
1743                         /* If the border select is initiated in the
1744                          * part of the action window where the channel
1745                          * names reside, then select the channels
1746                          */
1747                         if (mval[0]<ACTWIDTH){
1748                                 borderselect_function(mouse_actionchannels);
1749                         }
1750
1751                         /* If the border select is initiated in the
1752                          * vertical scrollbar, then (de)select all keys
1753                          * for the channels in the selection region
1754                          */
1755                         else if (IN_2D_VERT_SCROLL(mval)) {
1756                                 borderselect_function(select_all_keys_channels);
1757                         }
1758
1759                         /* If the border select is initiated in the
1760                          * horizontal scrollbar, then (de)select all keys
1761                          * for the keyframes in the selection region
1762                          */
1763                         else if (IN_2D_HORIZ_SCROLL(mval)) {
1764                                 borderselect_function(select_all_keys_frames);
1765                         }
1766
1767                         /* Other wise, select the action keys
1768                          */
1769                         else {
1770                                 borderselect_action();
1771                         }
1772                         break;
1773                 case RIGHTMOUSE:
1774                         /* Right clicking in the channel area selects the
1775                          * channel or constraint channel
1776                          */
1777                         if (mval[0]<ACTWIDTH) {
1778                                 if(G.qual & LR_SHIFTKEY)
1779                                         mouse_actionchannels(act, mval, NULL, 
1780                                                                                  SELECT_INVERT);
1781                                 else
1782                                         mouse_actionchannels(act, mval, NULL, 
1783                                                                                  SELECT_REPLACE);
1784                         }
1785
1786                         /* Right clicking in the vertical scrollbar selects
1787                          * all of the keys for that channel at that height
1788                          */
1789                         else if (IN_2D_VERT_SCROLL(mval)) {
1790                                 if(G.qual & LR_SHIFTKEY)
1791                                         select_all_keys_channels(act, mval, NULL, 
1792                                                                                          SELECT_INVERT);
1793                                 else
1794                                         select_all_keys_channels(act, mval, NULL, 
1795                                                                                          SELECT_REPLACE);
1796                         }
1797
1798                         /* Right clicking in the horizontal scrollbar selects
1799                          * all of the keys within 0.5 of the nearest integer
1800                          * frame
1801                          */
1802                         else if (IN_2D_HORIZ_SCROLL(mval)) {
1803                                 if(G.qual & LR_SHIFTKEY)
1804                                         select_all_keys_frames(act, mval, NULL, 
1805                                                                                    SELECT_INVERT);
1806                                 else
1807                                         select_all_keys_frames(act, mval, NULL, 
1808                                                                                    SELECT_REPLACE);
1809                         }
1810
1811                         /* Clicking in the main area of the action window
1812                          * selects keys
1813                          */
1814                         else {
1815                                 if(G.qual & LR_SHIFTKEY)
1816                                         mouse_action(SELECT_INVERT);
1817                                 else
1818                                         mouse_action(SELECT_REPLACE);
1819                         }
1820                         break;
1821
1822                 case LEFTMOUSE:
1823                         if (mval[0]>ACTWIDTH){
1824                                 do {
1825                                         getmouseco_areawin(mval);
1826                                         
1827                                         areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
1828                                         
1829                                         cfra= (int)dx;
1830                                         if(cfra< 1) cfra= 1;
1831                                         
1832                                         if( cfra!=CFRA ) {
1833                                                 CFRA= cfra;
1834                                                 update_for_newframe();
1835                                                 force_draw_plus(SPACE_VIEW3D);
1836                                                 force_draw_plus(SPACE_IPO);
1837                                                 force_draw_plus(SPACE_BUTS);
1838                                         }
1839                                         
1840                                 } while(get_mbut()&L_MOUSE);
1841                         }
1842                         
1843                         break;
1844                 case MIDDLEMOUSE:
1845                 case WHEELUPMOUSE:
1846                 case WHEELDOWNMOUSE:
1847                         view2dmove(event);      /* in drawipo.c */
1848                         break;
1849                 }
1850         }
1851
1852         if(doredraw) addqueue(curarea->win, REDRAW, 1);
1853         
1854 }
1855