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