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