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