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