01f0ff4ff2bd783f5bab0db6e9cc2a055484da97
[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         /* ton: added flag hilighted, for display in ipowin. dunno what the difference is between select/hilite */
776         achan->flag |= ACHAN_SELECTED|ACHAN_HILIGHTED;
777
778         /* Ensure this action channel has a valid Ipo */
779         if (!achan->ipo){
780                 sprintf (ipstr, "%s.%s", act->id.name+2, chan->name);
781                 ipstr[23]=0;
782                 achan->ipo=     add_ipo(ipstr, ID_AC);  
783         }
784
785         insertactionkey(act, achan, chan, adrcode, makecurve, time);
786
787 }
788
789 static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float cfra)
790 {
791         IpoCurve *icu;
792         void *poin;
793         float curval;
794         int type;
795         ID *id;
796         
797         if (!act){
798                 return;
799         }
800         if (act->id.lib){
801                 error ("Can't pose libactions");
802                 return;
803         }
804         act->achan=achan;
805         act->pchan=chan;
806
807         id=(ID*) act;
808
809         /* First see if this curve exists */
810         if (!makecurve){
811                 if (!achan->ipo)
812                         return;
813
814                 for (icu = achan->ipo->curve.first; icu; icu=icu->next){
815                         if (icu->adrcode == adrcode)
816                                 break;
817                 }
818                 if (!icu)
819                         return;
820         }
821
822         
823         icu = get_ipocurve (id, GS(id->name), adrcode, achan->ipo);
824
825         if(icu) {
826                 poin= get_ipo_poin(id, icu, &type);
827                 if(poin) {
828                         curval= read_ipo_poin(poin, type);
829         //              cfra= frame_to_float(CFRA);
830                         insert_vert_ipo(icu, cfra, curval);
831                 }
832         }
833         
834 }
835
836 bAction *add_empty_action(void)
837 {
838         bAction *act;
839
840         act= alloc_libblock(&G.main->action, ID_AC, "Action");
841         act->id.flag |= LIB_FAKEUSER;
842         act->id.us++;
843         return act;
844 }
845
846 static void transform_actionchannel_keys(char mode)
847 {
848         bAction *act;
849         TransVert *tv;
850         int /*sel=0,*/  i;
851         bActionChannel  *chan;
852         short   mvals[2], mvalc[2], cent[2];
853         float   sval[2], cval[2], lastcval[2];
854         short   cancel=0;
855         float   fac=0.0F;
856         int             loop=1;
857         int             tvtot=0;
858         float   deltax, startx;
859         float   cenf[2];
860         int             invert=0, firsttime=1;
861         char    str[256];
862         bConstraintChannel *conchan;
863
864         act=G.saction->action;
865
866         /* Ensure that partial selections result in beztriple selections */
867         for (chan=act->chanbase.first; chan; chan=chan->next){
868                 tvtot+=fullselect_ipo_keys(chan->ipo);
869
870                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
871                         tvtot+=fullselect_ipo_keys(conchan->ipo);
872         }
873         
874         /* If nothing is selected, bail out */
875         if (!tvtot)
876                 return;
877         
878         
879         /* Build the transvert structure */
880         tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
881         tvtot=0;
882         for (chan=act->chanbase.first; chan; chan=chan->next){
883                 /* Add the actionchannel */
884                 tvtot = add_trans_ipo_keys(chan->ipo, tv, tvtot);
885                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
886                         tvtot = add_trans_ipo_keys(conchan->ipo, tv, tvtot);
887         }
888
889         /* Do the event loop */
890         cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2;
891         cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2;
892         areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]);
893
894         getmouseco_areawin (mvals);
895         areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
896
897         startx=sval[0];
898         while (loop) {
899                 /*              Get the input */
900                 /*              If we're cancelling, reset transformations */
901                 /*                      Else calc new transformation */
902                 /*              Perform the transformations */
903                 while (qtest()) {
904                         short val;
905                         unsigned short event= extern_qread(&val);
906
907                         if (val) {
908                                 switch (event) {
909                                 case LEFTMOUSE:
910                                 case SPACEKEY:
911                                 case RETKEY:
912                                         loop=0;
913                                         break;
914                                 case XKEY:
915                                         break;
916                                 case ESCKEY:
917                                 case RIGHTMOUSE:
918                                         cancel=1;
919                                         loop=0;
920                                         break;
921                                 default:
922                                         arrows_move_cursor(event);
923                                         break;
924                                 };
925                         }
926                 }
927
928                 if (cancel) {
929                         for (i=0; i<tvtot; i++) {
930                                 tv[i].loc[0]=tv[i].oldloc[0];
931                                 tv[i].loc[1]=tv[i].oldloc[1];
932                         }
933                 } else {
934                         getmouseco_areawin (mvalc);
935                         areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
936
937                         if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
938                                 PIL_sleep_ms(1);
939                         } else {
940                                 for (i=0; i<tvtot; i++){
941                                         tv[i].loc[0]=tv[i].oldloc[0];
942
943                                         switch (mode){
944                                         case 'g':
945                                                 deltax = cval[0]-sval[0];
946                                                 fac= deltax;
947                                                 
948                                                 apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & AUTOGRABGRID);
949
950                                                 tv[i].loc[0]+=fac;
951                                                 break;
952                                         case 's':
953                                                 startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
954                                                 deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
955                                                 fac= fabs(deltax/startx);
956                                                 
957                                                 apply_keyb_grid(&fac, 0.0, 0.2, 0.1, U.flag & AUTOSIZEGRID);
958                 
959                                                 if (invert){
960                                                         if (i % 03 == 0){
961                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
962                                                         }
963                                                         if (i % 03 == 2){
964                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
965                                                         }
966         
967                                                         fac*=-1;
968                                                 }
969                                                 startx= (G.scene->r.cfra);
970                                         
971                                                 tv[i].loc[0]-= startx;
972                                                 tv[i].loc[0]*=fac;
973                                                 tv[i].loc[0]+= startx;
974                 
975                                                 break;
976                                         }
977                                 }
978                         }
979         
980                         if (mode=='s'){
981                                 sprintf(str, "sizeX: %.3f", fac);
982                                 headerprint(str);
983                         }
984                         else if (mode=='g'){
985                                 sprintf(str, "deltaX: %.3f", fac);
986                                 headerprint(str);
987                         }
988         
989                         if (G.saction->lock){
990                                 do_all_actions();
991                                 allqueue (REDRAWVIEW3D, 0);
992                                 allqueue (REDRAWACTION, 0);
993                                 allqueue (REDRAWIPO, 0);
994                                 allqueue(REDRAWNLA, 0);
995                                 force_draw_all();
996                         }
997                         else {
998                                 addqueue (curarea->win, REDRAWALL, 0);
999                                 force_draw ();
1000                         }
1001                 }
1002                 
1003                 lastcval[0]= cval[0];
1004                 lastcval[1]= cval[1];
1005                 firsttime= 0;
1006         }
1007         
1008         /*              Update the curve */
1009         /*              Depending on the lock status, draw necessary views */
1010
1011         do_all_actions();
1012         remake_action_ipos(act);
1013         allqueue (REDRAWVIEW3D, 0);
1014         allqueue (REDRAWACTION, 0);
1015         allqueue(REDRAWNLA, 0);
1016         allqueue (REDRAWIPO, 0);
1017         MEM_freeN (tv);
1018 }
1019
1020 void deselect_actionchannel_keys (bAction *act, int test)
1021 {
1022         bActionChannel  *chan;
1023         bConstraintChannel *conchan;
1024         int             sel=1;;
1025
1026         if (!act)
1027                 return;
1028
1029         /* Determine if this is selection or deselection */
1030         
1031         if (test){
1032                 for (chan=act->chanbase.first; chan; chan=chan->next){
1033                         /* Test the channel ipos */
1034                         if (is_ipo_key_selected(chan->ipo)){
1035                                 sel = 0;
1036                                 break;
1037                         }
1038
1039                         /* Test the constraint ipos */
1040                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1041                                 if (is_ipo_key_selected(conchan->ipo)){
1042                                         sel = 0;
1043                                         break;
1044                                 }
1045                         }
1046
1047                         if (sel == 0)
1048                                 break;
1049                 }
1050         }
1051         else
1052                 sel=0;
1053         
1054         /* Set the flags */
1055         for (chan=act->chanbase.first; chan; chan=chan->next){
1056                 set_ipo_key_selection(chan->ipo, sel);
1057                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1058                         set_ipo_key_selection(conchan->ipo, sel);
1059         }
1060 }
1061
1062 void deselect_actionchannels (bAction *act, int test)
1063 {
1064         bActionChannel *chan;
1065         bConstraintChannel *conchan;
1066         int                     sel=1;  
1067
1068         if (!act)
1069                 return;
1070
1071         /* See if we should be selecting or deselecting */
1072         if (test){
1073                 for (chan=act->chanbase.first; chan; chan=chan->next){
1074                         if (!sel)
1075                                 break;
1076
1077                         if (chan->flag & ACHAN_SELECTED){
1078                                 sel=0;
1079                                 break;
1080                         }
1081                         if (sel){
1082                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1083                                         if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1084                                                 sel=0;
1085                                                 break;
1086                                         }
1087                                 }
1088                         }
1089                 }
1090         }
1091         else
1092                 sel=0;
1093
1094         /* Now set the flags */
1095         for (chan=act->chanbase.first; chan; chan=chan->next){
1096                 select_poseelement_by_name(chan->name, sel);
1097
1098                 if (sel)
1099                         chan->flag |= ACHAN_SELECTED;
1100                 else
1101                         chan->flag &= ~ACHAN_SELECTED;
1102
1103                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1104                         if (sel)
1105                                 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1106                         else
1107                                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1108                 }
1109         }
1110
1111 }
1112
1113 static void hilight_channel (bAction *act, bActionChannel *chan, short select)
1114 {
1115         bActionChannel *curchan;
1116
1117         if (!act)
1118                 return;
1119
1120         for (curchan=act->chanbase.first; curchan; curchan=curchan->next){
1121                 if (curchan==chan && select)
1122                         curchan->flag |= ACHAN_HILIGHTED;
1123                 else
1124                         curchan->flag &= ~ACHAN_HILIGHTED;
1125         }
1126 }
1127
1128 static int select_channel(bAction *act, bActionChannel *chan,
1129                           int selectmode) {
1130         /* Select the channel based on the selection mode
1131          */
1132         int flag;
1133
1134         switch (selectmode) {
1135         case SELECT_ADD:
1136                 chan->flag |= ACHAN_SELECTED;
1137                 break;
1138         case SELECT_SUBTRACT:
1139                 chan->flag &= ~ACHAN_SELECTED;
1140                 break;
1141         case SELECT_INVERT:
1142                 chan->flag ^= ACHAN_SELECTED;
1143                 break;
1144         }
1145         flag = (chan->flag & ACHAN_SELECTED) ? 1 : 0;
1146
1147         hilight_channel(act, chan, flag);
1148         select_poseelement_by_name(chan->name, flag);
1149
1150         return flag;
1151 }
1152
1153 static int select_constraint_channel(bAction *act, 
1154                                      bConstraintChannel *conchan, 
1155                                      int selectmode) {
1156         /* Select the constraint channel based on the selection mode
1157          */
1158         int flag;
1159
1160         switch (selectmode) {
1161         case SELECT_ADD:
1162                 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1163                 break;
1164         case SELECT_SUBTRACT:
1165                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1166                 break;
1167         case SELECT_INVERT:
1168                 conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
1169                 break;
1170         }
1171         flag = (conchan->flag & CONSTRAINT_CHANNEL_SELECT) ? 1 : 0;
1172
1173         return flag;
1174 }
1175
1176
1177 static void mouse_actionchannels(bAction *act, short *mval,
1178                                  short *mvalo, int selectmode) {
1179         /* Select action channels, based on mouse values.
1180          * If mvalo is NULL we assume it is a one click
1181          * action, other wise we treat it like it is a
1182          * border select with mval[0],mval[1] and
1183          * mvalo[0], mvalo[1] forming the corners of
1184          * a rectangle.
1185          */
1186         bActionChannel *chan;
1187         float   click;
1188         int   clickmin, clickmax;
1189         int             wsize, sel;
1190         bConstraintChannel *conchan;
1191
1192         if (!act)
1193                 return;
1194   
1195         if (selectmode == SELECT_REPLACE) {
1196                 deselect_actionchannels (act, 0);
1197                 selectmode = SELECT_ADD;
1198         }
1199
1200         /* wsize is the greatest possible height (in pixels) that would be
1201          * needed to draw all of the action channels and constraint
1202          * channels.
1203          */
1204         wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP));
1205
1206         click = (wsize-(mval[1]+G.v2d->cur.ymin));
1207         click += CHANNELHEIGHT/2;
1208         click /= (CHANNELHEIGHT+CHANNELSKIP);
1209         
1210         clickmin = (int) click;
1211
1212         /* Only one click */
1213         if (mvalo == NULL) {
1214                 clickmax = clickmin;
1215         }
1216         /* Two click values (i.e., border select */
1217         else {
1218                 click = (wsize-(mvalo[1]+G.v2d->cur.ymin));
1219                 click += CHANNELHEIGHT/2;
1220                 click /= (CHANNELHEIGHT+CHANNELSKIP);
1221
1222                 if ( ((int) click) < clickmin) {
1223                         clickmax = clickmin;
1224                         clickmin = (int) click;
1225                 }
1226                 else {
1227                         clickmax = (int) click;
1228                 }
1229         }
1230
1231         if (clickmax < 0) {
1232                 return;
1233         }
1234
1235         /* clickmin and clickmax now coorespond to indices into
1236          * the collection of channels and constraint channels.
1237          * What we need to do is apply the selection mode on all
1238          * channels and constraint channels between these indices.
1239          * This is done by traversing the channels and constraint
1240          * channels, for each item decrementing clickmin and clickmax.
1241          * When clickmin is less than zero we start selecting stuff,
1242          * until clickmax is less than zero or we run out of channels
1243          * and constraint channels.
1244          */
1245
1246         for (chan = act->chanbase.first; chan; chan=chan->next){
1247                 if (clickmax < 0) break;
1248
1249                 if ( clickmin <= 0) {
1250                         /* Select the channel with the given mode. If the
1251                          * channel is freshly selected then set it to the
1252                          * active channel for the action
1253                          */
1254                         sel = (chan->flag & ACHAN_SELECTED);
1255                         if ( select_channel(act, chan, selectmode) && !sel ) {
1256                                 act->achan = chan;
1257                         }
1258                 }
1259                 --clickmin;
1260                 --clickmax;
1261
1262                 /* Check for click in a constraint */
1263                 for (conchan=chan->constraintChannels.first; 
1264                          conchan; conchan=conchan->next){
1265                         if (clickmax < 0) break;
1266                         if ( clickmin <= 0) {
1267                                 select_constraint_channel(act, conchan, selectmode);
1268                         }
1269                         --clickmin;
1270                         --clickmax;
1271                 }
1272         }
1273
1274         allqueue (REDRAWIPO, 0);
1275         allqueue (REDRAWVIEW3D, 0);
1276         allqueue (REDRAWACTION, 0);
1277         allqueue (REDRAWNLA, 0);
1278 }
1279
1280
1281 static void delete_actionchannel_keys(void)
1282 {
1283         bAction *act;
1284         bActionChannel *chan;
1285         bConstraintChannel *conchan;
1286
1287         act = G.saction->action;
1288         if (!act)
1289                 return;
1290
1291         if (!okee("Erase selected keys"))
1292                 return;
1293
1294         for (chan = act->chanbase.first; chan; chan=chan->next){
1295
1296                 /* Check action channel keys*/
1297                 delete_ipo_keys(chan->ipo);
1298
1299                 /* Delete constraint channel keys */
1300                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1301                         delete_ipo_keys(conchan->ipo);
1302         }
1303
1304         remake_action_ipos (act);
1305         allspace(REMAKEIPO, 0);
1306         allqueue(REDRAWACTION, 0);
1307         allqueue(REDRAWIPO, 0);
1308         allqueue(REDRAWNLA, 0);
1309
1310 }
1311 static void delete_actionchannels (void)
1312 {
1313         bConstraintChannel *conchan, *nextconchan;
1314         bActionChannel *chan, *next;
1315         bAction *act;
1316         int freechan;
1317
1318         act=G.saction->action;
1319
1320         if (!act)
1321                 return;
1322
1323         for (chan=act->chanbase.first; chan; chan=chan->next){
1324                 if (chan->flag & ACHAN_SELECTED)
1325                         break;
1326                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1327                 {
1328                         if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1329                                 chan=act->chanbase.last;
1330                                 break;
1331                         }
1332                 }
1333         }
1334
1335         if (!chan && !conchan)
1336                 return;
1337
1338         if (!okee("Erase selected channels"))
1339                 return;
1340
1341         for (chan=act->chanbase.first; chan; chan=next){
1342                 freechan = 0;
1343                 next=chan->next;
1344                 
1345                 /* Remove action channels */
1346                 if (chan->flag & ACHAN_SELECTED){
1347                         if (chan->ipo)
1348                                 chan->ipo->id.us--;     /* Release the ipo */
1349                         freechan = 1;
1350                 }
1351                 
1352                 /* Remove constraint channels */
1353                 for (conchan=chan->constraintChannels.first; conchan; conchan=nextconchan){
1354                         nextconchan=conchan->next;
1355                         if (freechan || conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1356                                 if (conchan->ipo)
1357                                         conchan->ipo->id.us--;
1358                                 BLI_freelinkN(&chan->constraintChannels, conchan);
1359                         }
1360                 }
1361                 
1362                 if (freechan)
1363                         BLI_freelinkN (&act->chanbase, chan);
1364
1365         }
1366
1367         allqueue (REDRAWACTION, 0);
1368         allqueue(REDRAWNLA, 0);
1369
1370 }
1371
1372 static void sethandles_actionchannel_keys(int code)
1373 {
1374         bAction *act;
1375         bActionChannel *chan;
1376
1377         /* Get the selected action, exit if none are selected 
1378          */
1379         act = G.saction->action;
1380         if (!act)
1381                 return;
1382
1383         /* Loop through the channels and set the beziers
1384          * of the selected keys based on the integer code
1385          */
1386         for (chan = act->chanbase.first; chan; chan=chan->next){
1387                 sethandles_ipo_keys(chan->ipo, code);
1388         }
1389
1390         /* Clean up and redraw stuff
1391          */
1392         remake_action_ipos (act);
1393         allspace(REMAKEIPO, 0);
1394         allqueue(REDRAWACTION, 0);
1395         allqueue(REDRAWIPO, 0);
1396         allqueue(REDRAWNLA, 0);
1397 }
1398
1399 static void set_ipotype_actionchannels(void) {
1400
1401         bAction *act; 
1402         bActionChannel *chan;
1403         short event;
1404
1405         /* Get the selected action, exit if none are selected 
1406          */
1407         act = G.saction->action;
1408         if (!act)
1409                 return;
1410
1411         /* Present a popup menu asking the user what type
1412          * of IPO curve he/she/GreenBTH wants. ;)
1413          */
1414         event= pupmenu("Channel Ipo Type %t|Constant %x1|Linear %x2|Bezier %x3");
1415         if(event < 1) return;
1416         
1417         /* Loop through the channels and for the selected ones set
1418          * the type for each Ipo curve in the channel Ipo (based on
1419          * the value from the popup).
1420          */
1421         for (chan = act->chanbase.first; chan; chan=chan->next){
1422                 if (chan->flag & ACHAN_SELECTED){
1423                         if (chan->ipo)
1424                                 setipotype_ipo(chan->ipo, event);
1425                 }
1426         }
1427
1428         /* Clean up and redraw stuff
1429          */
1430         remake_action_ipos (act);
1431         allspace(REMAKEIPO, 0);
1432         allqueue(REDRAWACTION, 0);
1433         allqueue(REDRAWIPO, 0);
1434         allqueue(REDRAWNLA, 0);
1435 }
1436
1437 void select_all_keys_frames(bAction *act, short *mval, 
1438                                                         short *mvalo, int selectmode) {
1439         
1440         /* This function tries to select all action keys in
1441          * every channel for a given range of keyframes that
1442          * are within the mouse values mval and mvalo (usually
1443          * the result of a border select). If mvalo is passed as
1444          * NULL then the selection is treated as a one-click and
1445          * the function tries to select all keys within half a
1446          * frame of the click point.
1447          */
1448         
1449         rcti rect;
1450         rctf rectf;
1451         bActionChannel *chan;
1452         bConstraintChannel *conchan;
1453
1454         if (!act)
1455                 return;
1456
1457         if (selectmode == SELECT_REPLACE) {
1458                 deselect_actionchannel_keys(act, 0);
1459                 selectmode = SELECT_ADD;
1460         }
1461
1462         if (mvalo == NULL) {
1463                 rect.xmin = rect.xmax = mval[0];
1464                 rect.ymin = rect.ymax = mval[1];
1465         }
1466         else {
1467                 if (mval[0] < mvalo[0] ) {
1468                         rect.xmin = mval[0];
1469                         rect.xmax = mvalo[0];
1470                 }
1471                 else {
1472                         rect.xmin = mvalo[0];
1473                         rect.xmax = mval[0];
1474                 }
1475                 if (mval[1] < mvalo[1] ) {
1476                         rect.ymin = mval[1];
1477                         rect.ymax = mvalo[1];
1478                 }
1479                 else {
1480                         rect.ymin = mvalo[1];
1481                         rect.ymax = mval[1];
1482                 }
1483         }
1484
1485         mval[0]= rect.xmin;
1486         mval[1]= rect.ymin+2;
1487         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1488         mval[0]= rect.xmax;
1489         mval[1]= rect.ymax-2;
1490         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1491
1492         if (mvalo == NULL) {
1493                 rectf.xmin = rectf.xmin - 0.5;
1494                 rectf.xmax = rectf.xmax + 0.5;
1495         }
1496     
1497         for (chan=act->chanbase.first; chan; chan=chan->next){
1498                 borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax,
1499                                                          selectmode);
1500                 for (conchan=chan->constraintChannels.first; conchan; 
1501                          conchan=conchan->next){
1502                         borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
1503                                                                  selectmode);
1504                 }
1505         }       
1506         allqueue(REDRAWNLA, 0);
1507         allqueue(REDRAWACTION, 0);
1508         allqueue(REDRAWIPO, 0);
1509 }
1510
1511
1512 void select_all_keys_channels(bAction *act, short *mval, 
1513                               short *mvalo, int selectmode) {
1514         bActionChannel    *chan;
1515         float              click;
1516         int                clickmin, clickmax;
1517         int                wsize;
1518         bConstraintChannel *conchan;
1519
1520         /* This function selects all the action keys that
1521          * are in the mouse selection range defined by
1522          * the ordered pairs mval and mvalo (usually
1523          * these 2 are obtained from a border select).
1524          * If mvalo is NULL, then the selection is
1525          * treated like a one-click action, and at most
1526          * one channel is selected.
1527          */
1528
1529         /* If the action is null then abort
1530          */
1531         if (!act)
1532                 return;
1533
1534         if (selectmode == SELECT_REPLACE) {
1535                 deselect_actionchannel_keys(act, 0);
1536                 selectmode = SELECT_ADD;
1537         }
1538
1539         /* wsize is the greatest possible height (in pixels) that would be
1540          * needed to draw all of the action channels and constraint
1541          * channels.
1542          */
1543         wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP));
1544
1545         click = (wsize-(mval[1]+G.v2d->cur.ymin));
1546         click += CHANNELHEIGHT/2;
1547         click /= (CHANNELHEIGHT+CHANNELSKIP);
1548
1549         clickmin = (int) click;
1550
1551         /* Only one click */
1552         if (mvalo == NULL) {
1553                 clickmax = clickmin;
1554         }
1555         /* Two click values (i.e., border select) */
1556         else {
1557                 click = (wsize-(mvalo[1]+G.v2d->cur.ymin));
1558                 click += CHANNELHEIGHT/2;
1559                 click /= (CHANNELHEIGHT+CHANNELSKIP);
1560
1561                 if ( ((int) click) < clickmin) {
1562                         clickmax = clickmin;
1563                         clickmin = (int) click;
1564                 }
1565                 else {
1566                         clickmax = (int) click;
1567                 }
1568         }
1569
1570         if (clickmax < 0) {
1571                 return;
1572         }
1573
1574         for (chan = act->chanbase.first; chan; chan=chan->next){
1575                 if (clickmax < 0) break;
1576
1577                 if ( clickmin <= 0) {
1578                         /* Select the channel with the given mode. If the
1579                          * channel is freshly selected then set it to the
1580                          * active channel for the action
1581                          */
1582                         select_ipo_bezier_keys(chan->ipo, selectmode);
1583                 }
1584                 --clickmin;
1585                 --clickmax;
1586
1587                 /* Check for click in a constraint */
1588                 for (conchan=chan->constraintChannels.first; 
1589                          conchan; conchan=conchan->next){
1590                         if (clickmax < 0) break;
1591                         if ( clickmin <= 0) {
1592                                 select_ipo_bezier_keys(chan->ipo, selectmode);
1593                         }
1594                         --clickmin;
1595                         --clickmax;
1596                 }
1597         }
1598   
1599         allqueue (REDRAWIPO, 0);
1600         allqueue (REDRAWVIEW3D, 0);
1601         allqueue (REDRAWACTION, 0);
1602         allqueue (REDRAWNLA, 0);
1603   
1604 }
1605
1606 static void borderselect_function(void (*select_func)(bAction *act, 
1607                                                      short *mval, 
1608                                                      short *mvalo, 
1609                                                      int selectmode)) {
1610         /* This function executes an arbitrary selection
1611          * function as part of a border select. This
1612          * way the same function that is used for
1613          * right click selection points can generally
1614          * be used as the argument to this function
1615          */
1616         rcti rect;
1617         short   mval[2], mvalo[2];
1618         bAction *act;
1619         int val;                
1620
1621         /* Get the selected action, exit if none are selected 
1622          */
1623         act=G.saction->action;
1624         if (!act)
1625                 return;
1626
1627         /* Let the user draw a border (or abort)
1628          */
1629         if ( (val=get_border (&rect, 3)) ) {
1630                 mval[0]= rect.xmin;
1631                 mval[1]= rect.ymin+2;
1632                 mvalo[0]= rect.xmax;
1633                 mvalo[1]= rect.ymax-2;
1634
1635                 /* if the left mouse was used, do an additive
1636                  * selection with the user defined selection
1637                  * function.
1638                  */
1639                 if (val == LEFTMOUSE)
1640                         select_func(act, mval, mvalo, SELECT_ADD);
1641                 
1642                 /* if the right mouse was used, do a subtractive
1643                  * selection with the user defined selection
1644                  * function.
1645                  */
1646                 else if (val == RIGHTMOUSE)
1647                         select_func(act, mval, mvalo, SELECT_SUBTRACT);
1648         }
1649         
1650 }
1651
1652 void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1653 {
1654         unsigned short event= evt->event;
1655         short val= evt->val;
1656         char ascii= evt->ascii;
1657         SpaceAction *saction;
1658         bAction *act;
1659         int doredraw= 0;
1660         short   mval[2];
1661         float dx,dy;
1662         int     cfra;
1663         
1664         if(curarea->win==0) return;
1665
1666         saction= curarea->spacedata.first;
1667         if (!saction)
1668                 return;
1669
1670         act=saction->action;
1671         if(val) {
1672                 
1673                 if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
1674                 
1675                 getmouseco_areawin(mval);
1676
1677                 switch(event) {
1678                 case UI_BUT_EVENT:
1679                         do_blenderbuttons(val);
1680                         break;
1681                 case HOMEKEY:
1682                         do_action_buttons(B_ACTHOME);
1683                         break;
1684
1685                 case CKEY:
1686                         /* scroll the window so the current
1687                          * frame is in the center.
1688                          */
1689                         center_currframe();
1690                         break;
1691
1692                 case DKEY:
1693                         if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH){
1694                                 duplicate_actionchannel_keys();
1695                                 remake_action_ipos(act);
1696                         }
1697                         break;
1698                 case DELKEY:
1699                 case XKEY:
1700                         if (mval[0]<ACTWIDTH)
1701                                 delete_actionchannels ();
1702                         else
1703                                 delete_actionchannel_keys ();
1704                         break;
1705                 case GKEY:
1706                         if (mval[0]>=ACTWIDTH)
1707                                 transform_actionchannel_keys ('g');
1708                         break;
1709                 case SKEY:
1710                         if (mval[0]>=ACTWIDTH)
1711                                 transform_actionchannel_keys ('s');
1712                         break;
1713                 case AKEY:
1714                         if (mval[0]<ACTWIDTH){
1715                                 deselect_actionchannels (act, 1);
1716                                 allqueue (REDRAWVIEW3D, 0);
1717                                 allqueue (REDRAWACTION, 0);
1718                                 allqueue(REDRAWNLA, 0);
1719                                 allqueue (REDRAWIPO, 0);
1720                         }
1721                         else{
1722                                 deselect_actionchannel_keys (act, 1);
1723                                 allqueue (REDRAWACTION, 0);
1724                                 allqueue(REDRAWNLA, 0);
1725                                 allqueue (REDRAWIPO, 0);
1726                         }
1727                         break;
1728
1729                         /*** set the Ipo handles ***/
1730                 case VKEY:
1731                         sethandles_actionchannel_keys(HD_VECT);
1732                         break;
1733                 case HKEY:
1734                         if(G.qual & LR_SHIFTKEY) sethandles_actionchannel_keys(HD_AUTO);
1735                         else sethandles_actionchannel_keys(HD_ALIGN);
1736                         break;
1737  
1738                         /*** set the Ipo type  ***/
1739                 case TKEY:
1740                         set_ipotype_actionchannels();
1741                         break;
1742
1743                 case BKEY:
1744                         /* If the border select is initiated in the
1745                          * part of the action window where the channel
1746                          * names reside, then select the channels
1747                          */
1748                         if (mval[0]<ACTWIDTH){
1749                                 borderselect_function(mouse_actionchannels);
1750                         }
1751
1752                         /* If the border select is initiated in the
1753                          * vertical scrollbar, then (de)select all keys
1754                          * for the channels in the selection region
1755                          */
1756                         else if (IN_2D_VERT_SCROLL(mval)) {
1757                                 borderselect_function(select_all_keys_channels);
1758                         }
1759
1760                         /* If the border select is initiated in the
1761                          * horizontal scrollbar, then (de)select all keys
1762                          * for the keyframes in the selection region
1763                          */
1764                         else if (IN_2D_HORIZ_SCROLL(mval)) {
1765                                 borderselect_function(select_all_keys_frames);
1766                         }
1767
1768                         /* Other wise, select the action keys
1769                          */
1770                         else {
1771                                 borderselect_action();
1772                         }
1773                         break;
1774                 case RIGHTMOUSE:
1775                         /* Right clicking in the channel area selects the
1776                          * channel or constraint channel
1777                          */
1778                         if (mval[0]<ACTWIDTH) {
1779                                 if(G.qual & LR_SHIFTKEY)
1780                                         mouse_actionchannels(act, mval, NULL, 
1781                                                                                  SELECT_INVERT);
1782                                 else
1783                                         mouse_actionchannels(act, mval, NULL, 
1784                                                                                  SELECT_REPLACE);
1785                         }
1786
1787                         /* Right clicking in the vertical scrollbar selects
1788                          * all of the keys for that channel at that height
1789                          */
1790                         else if (IN_2D_VERT_SCROLL(mval)) {
1791                                 if(G.qual & LR_SHIFTKEY)
1792                                         select_all_keys_channels(act, mval, NULL, 
1793                                                                                          SELECT_INVERT);
1794                                 else
1795                                         select_all_keys_channels(act, mval, NULL, 
1796                                                                                          SELECT_REPLACE);
1797                         }
1798
1799                         /* Right clicking in the horizontal scrollbar selects
1800                          * all of the keys within 0.5 of the nearest integer
1801                          * frame
1802                          */
1803                         else if (IN_2D_HORIZ_SCROLL(mval)) {
1804                                 if(G.qual & LR_SHIFTKEY)
1805                                         select_all_keys_frames(act, mval, NULL, 
1806                                                                                    SELECT_INVERT);
1807                                 else
1808                                         select_all_keys_frames(act, mval, NULL, 
1809                                                                                    SELECT_REPLACE);
1810                         }
1811
1812                         /* Clicking in the main area of the action window
1813                          * selects keys
1814                          */
1815                         else {
1816                                 if(G.qual & LR_SHIFTKEY)
1817                                         mouse_action(SELECT_INVERT);
1818                                 else
1819                                         mouse_action(SELECT_REPLACE);
1820                         }
1821                         break;
1822
1823                 case LEFTMOUSE:
1824                         if (mval[0]>ACTWIDTH){
1825                                 do {
1826                                         getmouseco_areawin(mval);
1827                                         
1828                                         areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
1829                                         
1830                                         cfra= (int)dx;
1831                                         if(cfra< 1) cfra= 1;
1832                                         
1833                                         if( cfra!=CFRA ) {
1834                                                 CFRA= cfra;
1835                                                 update_for_newframe();
1836                                                 force_draw_plus(SPACE_VIEW3D);
1837                                                 force_draw_plus(SPACE_IPO);
1838                                                 force_draw_plus(SPACE_BUTS);
1839                                         }
1840                                         
1841                                 } while(get_mbut()&L_MOUSE);
1842                         }
1843                         
1844                         break;
1845                 case MIDDLEMOUSE:
1846                 case WHEELUPMOUSE:
1847                 case WHEELDOWNMOUSE:
1848                         view2dmove(event);      /* in drawipo.c */
1849                         break;
1850                 }
1851         }
1852
1853         if(doredraw) addqueue(curarea->win, REDRAW, 1);
1854         
1855 }
1856