== Action/IPO Editors - Code Cleanup ==
[blender-staging.git] / source / blender / src / editipo_mods.c
1 /**
2  * $Id: 
3  *
4  * ***** BEGIN GPL 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.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2005. Full recode
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28
29 /* ********** Selection and set Handle code for editing Ipos in Blender ************* */
30 /*
31   mouse_select_ipo() is in editipo.c
32 */
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <math.h>
37
38 #ifndef WIN32
39 #include <unistd.h>
40 #else
41 #include <io.h>
42 #endif   
43
44 #include "BLI_blenlib.h"
45 #include "BLI_arithb.h"
46
47 #include "DNA_curve_types.h"
48 #include "DNA_ipo_types.h"
49 #include "DNA_key_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_view3d_types.h"
54
55 #include "BKE_global.h"
56 #include "BKE_action.h"
57 #include "BKE_ipo.h"
58 #include "BKE_key.h"
59 #include "BKE_utildefines.h"
60
61 #include "BIF_editaction.h"
62 #include "BIF_interface.h"
63 #include "BIF_screen.h"
64 #include "BIF_space.h"
65 #include "BIF_toolbox.h"
66
67 #include "BSE_edit.h"
68 #include "BSE_editipo_types.h"
69 #include "BSE_editipo.h"
70 #include "BSE_drawipo.h"
71 #include "BSE_trans_types.h"
72 #include "BSE_time.h"
73
74 #include "BDR_drawobject.h"
75
76 #include "blendef.h"
77 #include "mydevice.h"
78
79 extern int totipo_edit, totipo_sel, totipo_vertsel, totipo_vis;
80
81 void ipo_toggle_showkey(void) 
82 {
83         if(G.sipo->showkey) G.sipo->showkey= 0;
84         else G.sipo->showkey= 1;
85
86         free_ipokey(&G.sipo->ipokey);
87         if(G.sipo->ipo) G.sipo->ipo->showkey= G.sipo->showkey;
88         
89         BIF_undo_push("Toggle Show Key Ipo");
90 }
91
92 void swap_selectall_editipo(void)
93 {
94         Object *ob;
95         EditIpo *ei;
96         IpoKey *ik;
97         BezTriple *bezt;
98         int a, b; /*  , sel=0; */
99         
100         get_status_editipo();
101         
102         if(G.sipo->showkey) {
103                 ik= G.sipo->ipokey.first;
104                 while(ik) {
105                         if(totipo_vertsel) ik->flag &= ~1;
106                         else ik->flag |= 1;
107                         ik= ik->next;
108                 }
109                 update_editipo_flags();
110                 
111                 if(G.sipo->showkey && G.sipo->blocktype==ID_OB ) {
112                         ob= OBACT;
113                         if(ob && (ob->ipoflag & OB_DRAWKEY)) draw_object_ext(BASACT);
114                 }
115         }
116         else if(totipo_edit==0) {
117                 ei= G.sipo->editipo;
118                 if (ei){
119                         for(a=0; a<G.sipo->totipo; a++) {
120                                 if( ei->flag & IPO_VISIBLE ) {
121                                         if(totipo_sel) ei->flag &= ~IPO_SELECT;
122                                         else ei->flag |= IPO_SELECT;
123                                 }
124                                 ei++;
125                         }
126                         update_editipo_flags();
127                 }
128                 get_status_editipo();
129         }
130         else {
131                 ei= G.sipo->editipo;
132                 for(a=0; a<G.sipo->totipo; a++) {
133                         if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu )) {
134                                 bezt= ei->icu->bezt;
135                                 if(bezt) {
136                                         b= ei->icu->totvert;
137                                         while(b--) {
138                                                 if(totipo_vertsel) {
139                                                         bezt->f1= bezt->f2= bezt->f3= 0;
140                                                 }
141                                                 else {
142                                                         bezt->f1= bezt->f2= bezt->f3= 1;
143                                                 }
144                                                 bezt++;
145                                         }
146                                 }
147                         }
148                         ei++;
149                 }
150                 
151         }
152         
153         BIF_undo_push("Swap Select All Ipo");
154         scrarea_queue_winredraw(curarea);
155         
156 }
157
158 void swap_visible_editipo(void)
159 {
160         EditIpo *ei;
161         Object *ob;
162         int a; /*  , sel=0; */
163         
164         get_status_editipo();
165         
166         
167         ei= G.sipo->editipo;
168         for(a=0; a<G.sipo->totipo; a++) {
169                 if(totipo_vis==0) {
170                         if(ei->icu) {
171                                 ei->flag |= IPO_VISIBLE;
172                                 ei->flag |= IPO_SELECT;
173                         }
174                 }
175                 else 
176                         ei->flag &= ~IPO_VISIBLE;
177                 ei++;
178         }
179         
180         update_editipo_flags();
181         
182         if(G.sipo->showkey) {
183                 
184                 make_ipokey();
185                 
186                 ob= OBACT;
187                 if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
188         }
189         
190         scrarea_queue_winredraw(curarea);
191         BIF_undo_push("Swap Visible Ipo");      
192 }
193
194 void deselectall_editipo(void)
195 {
196         EditIpo *ei;
197         IpoKey *ik;
198         BezTriple *bezt;
199         int a, b; /*  , sel=0; */
200         
201         get_status_editipo();
202         
203         if(G.sipo->showkey) {
204                 ik= G.sipo->ipokey.first;
205                 while(ik) {
206                         ik->flag &= ~1;
207                         ik= ik->next;
208                 }
209                 update_editipo_flags();
210                 
211         }
212         else if(totipo_edit==0) {
213                 
214                 ei= G.sipo->editipo;
215                 for(a=0; a<G.sipo->totipo; a++) {
216                         if( ei->flag & IPO_VISIBLE ) {
217                                 ei->flag &= ~IPO_SELECT;
218                         }
219                         ei++;
220                 }
221                 update_editipo_flags();
222         }
223         else {
224                 ei= G.sipo->editipo;
225                 for(a=0; a<G.sipo->totipo; a++) {
226                         if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu )) {
227                                 if(ei->icu->bezt) {
228                                         bezt= ei->icu->bezt;
229                                         b= ei->icu->totvert;
230                                         while(b--) {
231                                                 bezt->f1= bezt->f2= bezt->f3= 0;
232                                                 bezt++;
233                                         }
234                                 }
235                         }
236                         ei++;
237                 }
238         }
239         
240         BIF_undo_push("(De)select all Ipo");
241         scrarea_queue_winredraw(curarea);
242 }
243
244
245 static int icu_keys_bezier_loop(IpoCurve *icu,
246                          int (*bezier_function)(BezTriple *),
247                          void (ipocurve_function)(struct IpoCurve *icu)) 
248 {
249     /*  This loops through the beziers in the Ipocurve, and executes 
250      *  the generic user provided 'bezier_function' on each one. 
251      *  Optionally executes the generic function ipocurve_function on the 
252      *  IPO curve after looping (eg. calchandles_ipocurve)
253      */
254
255     int b;
256     BezTriple *bezt;
257
258     b    = icu->totvert;
259     bezt = icu->bezt;
260
261     /* if bezier_function has been specified
262      * then loop through each bezier executing
263      * it.
264      */
265
266     if (bezier_function != NULL) {
267         while(b--) {
268             /* exit with return code 1 if the bezier function 
269              * returns 1 (good for when you are only interested
270              * in finding the first bezier that
271              * satisfies a condition).
272              */
273             if (bezier_function(bezt)) return 1;
274             bezt++;
275         }
276     }
277
278     /* if ipocurve_function has been specified 
279      * then execute it
280      */
281     if (ipocurve_function != NULL)
282         ipocurve_function(icu);
283
284     return 0;
285
286 }
287
288 static int ipo_keys_bezier_loop(Ipo *ipo,
289                          int (*bezier_function)(BezTriple *),
290                          void (ipocurve_function)(struct IpoCurve *icu))
291 {
292     /*  This loops through the beziers that are attached to
293      *  the selected keys on the Ipocurves of the Ipo, and executes 
294      *  the generic user provided 'bezier_function' on each one. 
295      *  Optionally executes the generic function ipocurve_function on a 
296      *  IPO curve after looping (eg. calchandles_ipocurve)
297      */
298
299     IpoCurve *icu;
300         
301         if(ipo==NULL) return 0;
302         
303     /* Loop through each curve in the Ipo
304      */
305     for (icu=ipo->curve.first; icu; icu=icu->next){
306         if (icu_keys_bezier_loop(icu,bezier_function, ipocurve_function))
307             return 1;
308     }
309
310     return 0;
311 }
312
313 static int selected_bezier_loop(int (*looptest)(EditIpo *),
314                          int (*bezier_function)(BezTriple *),
315                          void (ipocurve_function)(struct IpoCurve *icu))
316 {
317         /*  This loops through the beziers that are attached to
318          *  selected keys in editmode in the IPO window, and executes 
319          *  the generic user-provided 'bezier_function' on each one 
320          *  that satisfies the 'looptest' function. Optionally executes
321          *  the generic function ipocurve_function on a IPO curve
322          *  after looping (eg. calchandles_ipocurve)
323          */
324
325         EditIpo *ei;
326         BezTriple *bezt;
327         int a, b;
328
329         /* Get the first Edit Ipo from the selected Ipos
330          */
331         ei= G.sipo->editipo;
332
333         /* Loop throught all of the selected Ipo's
334          */
335         for(a=0; a<G.sipo->totipo; a++, ei++) {
336                 /* Do a user provided test on the Edit Ipo
337                  * to determine whether we want to process it
338                  */
339                 if (looptest(ei)) {
340                         /* Loop through the selected
341                          * beziers on the Edit Ipo
342                          */
343                         bezt = ei->icu->bezt;
344                         b    = ei->icu->totvert;
345                         
346                         /* if bezier_function has been specified
347                          * then loop through each bezier executing
348                          * it.
349                          */
350                         if (bezier_function != NULL) {
351                                 while(b--) {
352                                         /* exit with return code 1 if the bezier function 
353                                          * returns 1 (good for when you are only interested
354                                          * in finding the first bezier that
355                                          * satisfies a condition).
356                                          */
357                                         if (bezier_function(bezt)) return 1;
358                                         bezt++;
359                                 }
360                         }
361
362                         /* if ipocurve_function has been specified 
363                          * then execute it
364                          */
365                         if (ipocurve_function != NULL)
366                                 ipocurve_function(ei->icu);
367                 }
368                 /* nufte flourdje zim ploopydu <-- random dutch looking comment ;) */
369                 /* looks more like russian to me! (ton) */
370         }
371
372         return 0;
373 }
374
375 int select_bezier_add(BezTriple *bezt) 
376 {
377         /* Select the bezier triple */
378         bezt->f1 |= 1;
379         bezt->f2 |= 1;
380         bezt->f3 |= 1;
381         return 0;
382 }
383
384 int select_bezier_subtract(BezTriple *bezt) 
385 {
386         /* Deselect the bezier triple */
387         bezt->f1 &= ~1;
388         bezt->f2 &= ~1;
389         bezt->f3 &= ~1;
390         return 0;
391 }
392
393 int select_bezier_invert(BezTriple *bezt) 
394 {
395         /* Invert the selection for the bezier triple */
396         bezt->f2 ^= 1;
397         if ( bezt->f2 & 1 ) {
398                 bezt->f1 |= 1;
399                 bezt->f3 |= 1;
400         }
401         else {
402                 bezt->f1 &= ~1;
403                 bezt->f3 &= ~1;
404         }
405         return 0;
406 }
407
408 static int set_bezier_auto(BezTriple *bezt) 
409 {
410         /* Sets the selected bezier handles to type 'auto' 
411          */
412
413         /* is a handle selected? If so
414          * set it to type auto
415          */
416         if(bezt->f1 || bezt->f3) {
417                 if(bezt->f1) bezt->h1= 1; /* the secret code for auto */
418                 if(bezt->f3) bezt->h2= 1;
419
420                 /* if the handles are not of the same type, set them
421                  * to type free
422                  */
423                 if(bezt->h1!=bezt->h2) {
424                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
425                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
426                 }
427         }
428         return 0;
429 }
430
431 static int set_bezier_vector(BezTriple *bezt) 
432 {
433         /* Sets the selected bezier handles to type 'vector' 
434          */
435
436         /* is a handle selected? If so
437          * set it to type vector
438          */
439         if(bezt->f1 || bezt->f3) {
440                 if(bezt->f1) bezt->h1= 2; /* the code for vector */
441                 if(bezt->f3) bezt->h2= 2;
442     
443                 /* if the handles are not of the same type, set them
444                  * to type free
445                  */
446                 if(bezt->h1!=bezt->h2) {
447                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
448                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
449                 }
450         }
451         return 0;
452 }
453
454 static int bezier_isfree(BezTriple *bezt) 
455 {
456         /* queries whether the handle should be set
457          * to type 'free' (I think)
458          */
459         if(bezt->f1 && bezt->h1) return 1;
460         if(bezt->f3 && bezt->h2) return 1;
461         return 0;
462 }
463
464 static int set_bezier_free(BezTriple *bezt) 
465 {
466         /* Sets selected bezier handles to type 'free' 
467          */
468         if(bezt->f1) bezt->h1= HD_FREE;
469         if(bezt->f3) bezt->h2= HD_FREE;
470         return 0;
471 }
472
473 static int set_bezier_align(BezTriple *bezt) 
474 {
475         /* Sets selected bezier handles to type 'align' 
476          */
477         if(bezt->f1) bezt->h1= HD_ALIGN;
478         if(bezt->f3) bezt->h2= HD_ALIGN;
479         return 0;
480 }
481
482 static int vis_edit_icu_bez(EditIpo *ei) 
483 {
484         /* A 4 part test for an EditIpo :
485          *   is it a) visible
486          *         b) in edit mode
487          *         c) does it contain an Ipo Curve
488          *         d) does that ipo curve have a bezier
489          *
490          * (The reason why I don't just use the macro
491          * is I need a pointer to a function.)
492          */
493         return (ISPOIN4(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu, icu->bezt));
494 }
495
496 void select_ipo_bezier_keys(Ipo *ipo, int selectmode)
497 {
498         /* Select all of the beziers in all
499         * of the Ipo curves belonging to the
500         * Ipo, using the selection mode.
501         */
502         switch (selectmode) {
503                 case SELECT_ADD:
504                         ipo_keys_bezier_loop(ipo, select_bezier_add, NULL);
505                         break;
506                 case SELECT_SUBTRACT:
507                         ipo_keys_bezier_loop(ipo, select_bezier_subtract, NULL);
508                         break;
509                 case SELECT_INVERT:
510                         ipo_keys_bezier_loop(ipo, select_bezier_invert, NULL);
511                         break;
512         }
513 }
514
515 void select_icu_bezier_keys(IpoCurve *icu, int selectmode)
516 {
517         /* Select all of the beziers in all
518         * of the Ipo curves belonging to the
519         * Ipo, using the selection mode.
520         */
521         switch (selectmode) {
522                 case SELECT_ADD:
523                         icu_keys_bezier_loop(icu, select_bezier_add, NULL);
524                         break;
525                 case SELECT_SUBTRACT:
526                         icu_keys_bezier_loop(icu, select_bezier_subtract, NULL);
527                         break;
528                 case SELECT_INVERT:
529                         icu_keys_bezier_loop(icu, select_bezier_invert, NULL);
530                         break;
531         }
532 }
533
534 void sethandles_ipo_keys(Ipo *ipo, int code)
535 {
536         /* this function lets you set bezier handles all to
537          * one type for some Ipo's (e.g. with hotkeys through
538          * the action window).
539          */ 
540
541         /* code==1: set autohandle */
542         /* code==2: set vectorhandle */
543         /* als code==3 (HD_ALIGN) toggelt het, vectorhandles worden HD_FREE */
544         
545         switch(code) {
546         case 1:
547                 /*** Set to auto ***/
548                 ipo_keys_bezier_loop(ipo, set_bezier_auto,
549                                                          calchandles_ipocurve);
550                 break;
551         case 2:
552                 /*** Set to vector ***/
553                 ipo_keys_bezier_loop(ipo, set_bezier_vector,
554                          calchandles_ipocurve);
555                 break;
556         default:
557                 if ( ipo_keys_bezier_loop(ipo, bezier_isfree, NULL) ) {
558                         /*** Set to free ***/
559                         ipo_keys_bezier_loop(ipo, set_bezier_free,
560                            calchandles_ipocurve);
561                 }
562                 else {
563                         /*** Set to align ***/
564                         ipo_keys_bezier_loop(ipo, set_bezier_align,
565                            calchandles_ipocurve);
566                 }
567                 break;
568         }
569 }
570
571 static int snap_bezier_nearest(BezTriple *bezt)
572 {
573         if(bezt->f2 & SELECT)
574                 bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
575         return 0;
576 }
577
578 static int snap_bezier_cframe(BezTriple *bezt)
579 {
580         if(bezt->f2 & SELECT)
581                 bezt->vec[1][0]= (float)CFRA;
582         return 0;
583 }
584
585 static int snap_bezier_nearmarker(BezTriple *bezt)
586 {
587         if(bezt->f2 & SELECT)
588                 bezt->vec[1][0]= (float)find_nearest_marker_time(bezt->vec[1][0]);
589         
590         return 0;
591 }
592
593 void snap_ipo_keys(Ipo *ipo, short snaptype)
594 {
595         switch (snaptype) {
596                 case 1: /* snap to nearest */
597                         ipo_keys_bezier_loop(ipo, snap_bezier_nearest, calchandles_ipocurve);
598                         break;
599                 case 2: /* snap to current frame */
600                         ipo_keys_bezier_loop(ipo, snap_bezier_cframe, calchandles_ipocurve);
601                         break;
602                 case 3: /* snap to nearest marker */
603                         ipo_keys_bezier_loop(ipo, snap_bezier_nearmarker, calchandles_ipocurve);
604                         break;
605                 default: /* just in case */
606                         ipo_keys_bezier_loop(ipo, snap_bezier_nearest, calchandles_ipocurve);
607                         break;
608         }
609 }
610
611 static int mirror_bezier_cframe(BezTriple *bezt)
612 {
613         float diff;
614         
615         if(bezt->f2 & SELECT) {
616                 diff= ((float)CFRA - bezt->vec[1][0]);
617                 bezt->vec[1][0]= ((float)CFRA + diff);
618         }
619         
620         return 0;
621 }
622
623 static int mirror_bezier_yaxis(BezTriple *bezt)
624 {
625         float diff;
626         
627         if(bezt->f2 & SELECT) {
628                 diff= (0.0f - bezt->vec[1][0]);
629                 bezt->vec[1][0]= (0.0f + diff);
630         }
631         
632         return 0;
633 }
634
635 static int mirror_bezier_xaxis(BezTriple *bezt)
636 {
637         float diff;
638         
639         if(bezt->f2 & SELECT) {
640                 diff= (0.0f - bezt->vec[1][1]);
641                 bezt->vec[1][1]= (0.0f + diff);
642         }
643         
644         return 0;
645 }
646
647 static int mirror_bezier_marker(BezTriple *bezt)
648 {
649         static TimeMarker *marker;
650         static short initialised = 0;
651         float diff;
652         
653         /* In order for this mirror function to work without
654          * any extra arguments being added, we use the case
655          * of bezt==NULL to denote that we should find the 
656          * marker to mirror over. The static pointer is safe
657          * to use this way, as it will be set to null after 
658          * each cycle in which this is called.
659          */
660         
661         if (bezt) {
662                 /* mirroring time */
663                 if((bezt->f2 & SELECT) && (marker)) {
664                         diff= (marker->frame - bezt->vec[1][0]);
665                         bezt->vec[1][0]= (marker->frame + diff);
666                 }
667         }
668         else {
669                 /* initialisation time */
670                 if (initialised) {
671                         /* reset everything for safety */
672                         marker = NULL;
673                         initialised = 0;
674                 }
675                 else {
676                         /* try to find a marker */
677                         for (marker= G.scene->markers.first; marker; marker=marker->next) {
678                                 if (marker->flag & SELECT) {
679                                         initialised = 1;
680                                         break;
681                                 }
682                         }
683                         
684                         if (initialised == 0) 
685                                 marker = NULL;
686                 }
687         }
688         
689         return 0;
690 }
691
692 void mirror_ipo_keys(Ipo *ipo, short mirror_type)
693 {
694         switch (mirror_type) {
695                 case 1: /* mirror over current frame */
696                         ipo_keys_bezier_loop(ipo, mirror_bezier_cframe, calchandles_ipocurve);
697                         break;
698                 case 2: /* mirror over frame 0 */
699                         ipo_keys_bezier_loop(ipo, mirror_bezier_yaxis, calchandles_ipocurve);
700                         break;
701                 case 3: /* mirror over value 0 */
702                         ipo_keys_bezier_loop(ipo, mirror_bezier_xaxis, calchandles_ipocurve);
703                         break;
704                 case 4: /* mirror over marker */
705                         mirror_bezier_marker(NULL);
706                         ipo_keys_bezier_loop(ipo, mirror_bezier_marker, calchandles_ipocurve);
707                         mirror_bezier_marker(NULL);
708                         break;
709                 default: /* just in case */
710                         ipo_keys_bezier_loop(ipo, mirror_bezier_yaxis, calchandles_ipocurve);
711                         break;
712         }
713 }
714
715 /* currently only used by some action editor tools, but may soon get used by ipo editor */
716 /* restore = whether to map points back to ipo-time 
717  * only_keys = whether to only adjust the location of the center point of beztriples
718  */
719 void actstrip_map_ipo_keys(Object *ob, Ipo *ipo, short restore, short only_keys)
720 {
721         IpoCurve *icu;
722         BezTriple *bezt;
723         int a;
724         
725         if (ipo==NULL) return;
726         
727         /* loop through all ipo curves, adjusting the times of the selected keys */
728         for (icu= ipo->curve.first; icu; icu= icu->next) {
729                 for (a=0, bezt=icu->bezt; a<icu->totvert; a++, bezt++) {
730                         /* are the times being adjusted for editing, or has editing finished */
731                         if (restore) {
732                                 if (only_keys == 0) {
733                                         bezt->vec[0][0]= get_action_frame(ob, bezt->vec[0][0]);
734                                         bezt->vec[2][0]= get_action_frame(ob, bezt->vec[2][0]);
735                                 }                                       
736                                 bezt->vec[1][0]= get_action_frame(ob, bezt->vec[1][0]);
737                         }
738                         else {
739                                 if (only_keys == 0) {
740                                         bezt->vec[0][0]= get_action_frame_inv(ob, bezt->vec[0][0]);
741                                         bezt->vec[2][0]= get_action_frame_inv(ob, bezt->vec[2][0]);
742                                 }
743                                 bezt->vec[1][0]= get_action_frame_inv(ob, bezt->vec[1][0]);
744                         }
745                 }
746         }
747 }
748
749 static void ipo_curves_auto_horiz(void)
750 {
751     EditIpo *ei;
752         int a, set= 1;
753         
754         ei= G.sipo->editipo;
755         for(a=0; a<G.sipo->totipo; a++, ei++) {
756                 if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu))
757                         if(ei->flag & IPO_AUTO_HORIZ) set= 0;
758         }
759         
760         ei= G.sipo->editipo;
761         for(a=0; a<G.sipo->totipo; a++, ei++) {
762                 if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
763                         if(set) ei->flag |= IPO_AUTO_HORIZ;
764                         else ei->flag &= ~IPO_AUTO_HORIZ;
765                 }
766         }
767         update_editipo_flags();
768 }
769
770 void sethandles_ipo(int code)
771 {
772         /* this function lets you set bezier handles all to
773          * one type for some selected keys in edit mode in the
774          * IPO window (e.g. with hotkeys)
775          */ 
776
777         /* code==1: set autohandle */
778         /* code==2: set vectorhandle */
779         /* als code==3 (HD_ALIGN) toggelt het, vectorhandles worden HD_FREE */
780
781         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
782
783         switch(code) {
784         case HD_AUTO:
785                 /*** Set to auto ***/
786                 selected_bezier_loop(vis_edit_icu_bez, set_bezier_auto,
787                          calchandles_ipocurve);
788                 break;
789         case HD_VECT:
790                 /*** Set to vector ***/
791                 selected_bezier_loop(vis_edit_icu_bez, set_bezier_vector,
792                          calchandles_ipocurve);
793                 break;
794         case HD_AUTO_ANIM:
795                 /* set to enforce autohandles to be horizontal on extremes */
796                 ipo_curves_auto_horiz();
797                 
798                 break;
799         default:
800                 if (selected_bezier_loop(vis_edit_icu_bez, bezier_isfree, NULL) ) {
801                         /*** Set to free ***/
802                         selected_bezier_loop(vis_edit_icu_bez, set_bezier_free,
803                                                                  calchandles_ipocurve);
804                 }
805                 else {
806                         /*** Set to align ***/
807                         selected_bezier_loop(vis_edit_icu_bez, set_bezier_align,
808                                                                  calchandles_ipocurve);
809                 }
810                 break;
811         }
812
813         editipo_changed(G.sipo, 1);
814         BIF_undo_push("Set handles Ipo");
815 }
816
817
818 static void set_ipocurve_constant(struct IpoCurve *icu) {
819         /* Sets the type of the IPO curve to constant
820          */
821         icu->ipo= IPO_CONST;
822 }
823
824 static void set_ipocurve_linear(struct IpoCurve *icu) {
825         /* Sets the type of the IPO curve to linear
826          */
827         icu->ipo= IPO_LIN;
828 }
829
830 static void set_ipocurve_bezier(struct IpoCurve *icu) {
831         /* Sets the type of the IPO curve to bezier
832          */
833         
834         /* dont regenerate hendels for bezier ipo curves */
835         if (icu->ipo==IPO_BEZ) return;
836         
837         /* curve handels aren't generated for non bezier curve types */
838         icu->ipo= IPO_BEZ;
839         calchandles_ipocurve(icu);
840 }
841
842
843 void setipotype_ipo(Ipo *ipo, int code)
844 {
845         /* Sets the type of the each ipo curve in the
846          * Ipo to a value based on the code
847          */
848         switch (code) {
849         case 1:
850                 ipo_keys_bezier_loop(ipo, NULL, set_ipocurve_constant);
851                 break;
852         case 2:
853                 ipo_keys_bezier_loop(ipo, NULL, set_ipocurve_linear);
854                 break;
855         case 3:
856                 ipo_keys_bezier_loop(ipo, NULL, set_ipocurve_bezier);
857                 break;
858         }
859 }
860
861 void setexprap_ipoloop(Ipo *ipo, int code)
862 {
863         IpoCurve *icu;
864
865         /* Loop through each curve in the Ipo
866         */
867         for (icu=ipo->curve.first; icu; icu=icu->next)
868                 icu->extrap= code;
869 }
870
871 void set_ipotype(void)
872 {
873         EditIpo *ei;
874         int a;
875         short event;
876
877         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
878         if(G.sipo->showkey) return;
879         get_status_editipo();
880         
881         if(G.sipo->blocktype==ID_KE && totipo_edit==0 && totipo_sel==0) {
882                 Key *key= ob_get_key((Object *)G.sipo->from);
883                 Object *ob= OBACT;
884                 KeyBlock *kb;
885                 
886                 if(key==NULL) return;
887                 kb= BLI_findlink(&key->block, ob->shapenr-1);
888                 if(kb==NULL) return;
889                 
890                 event= pupmenu("Key Type %t|Linear %x1|Cardinal %x2|B Spline %x3");
891                 if(event < 1) return;
892
893                 kb->type= 0;
894                 if(event==1) kb->type= KEY_LINEAR;
895                 if(event==2) kb->type= KEY_CARDINAL;
896                 if(event==3) kb->type= KEY_BSPLINE;
897         }
898         else {
899                 event= pupmenu("Ipo Type %t|Constant %x1|Linear %x2|Bezier %x3");
900                 if(event < 1) return;
901                 
902                 ei= G.sipo->editipo;
903                 for(a=0; a<G.sipo->totipo; a++, ei++) {
904                         if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
905                                 if(event==1) ei->icu->ipo= IPO_CONST;
906                                 else if(event==2) ei->icu->ipo= IPO_LIN;
907                                 else ei->icu->ipo= IPO_BEZ;
908                         }
909                 }
910         }
911         BIF_undo_push("Set ipo type");
912         scrarea_queue_winredraw(curarea);
913 }
914
915 void borderselect_ipo(void)
916 {
917         EditIpo *ei;
918         IpoKey *ik;
919         BezTriple *bezt;
920         rcti rect;
921         rctf rectf;
922         int a, b, val;
923         short mval[2];
924
925         get_status_editipo();
926         
927         val= get_border(&rect, 3);
928
929         if(val) {
930                 /* map ipo-points for editing if scaled ipo */
931                 if (NLA_IPO_SCALED) {
932                         actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
933                 }
934                 
935                 mval[0]= rect.xmin;
936                 mval[1]= rect.ymin;
937                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
938                 mval[0]= rect.xmax;
939                 mval[1]= rect.ymax;
940                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
941                 
942                 if(G.sipo->showkey) {
943                         ik= G.sipo->ipokey.first;
944                         while(ik) {
945                                 if(rectf.xmin<ik->val && rectf.xmax>ik->val) {
946                                         if(val==LEFTMOUSE) ik->flag |= 1;
947                                         else ik->flag &= ~1;
948                                 }
949                                 ik= ik->next;
950                         }
951                         update_editipo_flags();
952                 }
953                 else if(totipo_edit==0) {
954                         if(rect.xmin<rect.xmax && rect.ymin<rect.ymax)
955                                 select_proj_ipo(&rectf, val);
956                 }
957                 else {
958                         
959                         ei= G.sipo->editipo;
960                         for(a=0; a<G.sipo->totipo; a++, ei++) {
961                                 if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu)) {
962                                         if(ei->icu->bezt) {
963                                                 b= ei->icu->totvert;
964                                                 bezt= ei->icu->bezt;
965                                                 while(b--) {
966                                                         int bit= (val==LEFTMOUSE);
967                                                         
968                                                         if(BLI_in_rctf(&rectf, bezt->vec[0][0], bezt->vec[0][1]))
969                                                                 bezt->f1 = (bezt->f1&~1) | bit;
970                                                         if(BLI_in_rctf(&rectf, bezt->vec[1][0], bezt->vec[1][1]))
971                                                                 bezt->f2 = (bezt->f2&~1) | bit;
972                                                         if(BLI_in_rctf(&rectf, bezt->vec[2][0], bezt->vec[2][1]))
973                                                                 bezt->f3 = (bezt->f3&~1) | bit;
974
975                                                         bezt++;
976                                                 }
977                                         }
978                                 }
979                         }
980                 }
981                 
982                 /* undo mapping of ipo-points for drawing if scaled ipo */
983                 if (NLA_IPO_SCALED) {
984                         actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 0);
985                 }
986                 
987                 BIF_undo_push("Border select Ipo");
988                 allqueue(REDRAWIPO, 0);
989                 allqueue(REDRAWACTION, 0);
990                 allqueue(REDRAWNLA, 0);
991         }
992 }
993
994
995
996 void nextkey(ListBase *elems, int dir)
997 {
998         IpoKey *ik, *previk;
999         int totsel;
1000         
1001         if(dir==1) ik= elems->last;
1002         else ik= elems->first;
1003         previk= 0;
1004         totsel= 0;
1005         
1006         while(ik) {
1007                 
1008                 if(ik->flag) totsel++;
1009                 
1010                 if(previk) {
1011                         if(G.qual & LR_SHIFTKEY) {
1012                                 if(ik->flag) previk->flag= 1;
1013                         }
1014                         else previk->flag= ik->flag;
1015                 }
1016                 
1017                 previk= ik;
1018                 if(dir==1) ik= ik->prev;
1019                 else ik= ik->next;
1020                 
1021                 if(G.qual & LR_SHIFTKEY);
1022                 else if(ik==0) previk->flag= 0;
1023         }
1024         
1025         /* when no key select: */
1026         if(totsel==0) {
1027                 if(dir==1) ik= elems->first;
1028                 else ik= elems->last;
1029                 
1030                 if(ik) ik->flag= 1;
1031         }
1032 }
1033
1034
1035 void nextkey_ipo(int dir)                       /* call from ipo queue */
1036 {
1037         IpoKey *ik;
1038         int a;
1039         
1040         if(G.sipo->showkey==0) return;
1041         
1042         nextkey(&G.sipo->ipokey, dir);
1043         
1044         /* copy to beziers */
1045         ik= G.sipo->ipokey.first;
1046         while(ik) {
1047                 for(a=0; a<G.sipo->totipo; a++) {
1048                         if(ik->data[a]) ik->data[a]->f1= ik->data[a]->f2= ik->data[a]->f3= ik->flag;
1049                 }
1050                 ik= ik->next;
1051         }               
1052         
1053         allqueue(REDRAWNLA, 0);
1054         allqueue(REDRAWACTION, 0);
1055         allqueue(REDRAWIPO, 0);
1056         if(G.sipo->blocktype == ID_OB) allqueue(REDRAWVIEW3D, 0);
1057 }
1058
1059 void nextkey_obipo(int dir)             /* only call external from view3d queue */
1060 {
1061         Base *base;
1062         Object *ob;
1063         ListBase elems;
1064         IpoKey *ik;
1065         int a;
1066         
1067         if (!G.vd) {
1068                 error("Can't do this! Open a 3D window");
1069                 return;
1070         }
1071         
1072         /* problem: this doesnt work when you mix dLoc keys with Loc keys */
1073         
1074         base= FIRSTBASE;
1075         while(base) {
1076                 if TESTBASE(base) {
1077                         ob= base->object;
1078                         if( (ob->ipoflag & OB_DRAWKEY) && ob->ipo && ob->ipo->showkey) {
1079                                 elems.first= elems.last= 0;
1080                                 make_ipokey_transform(ob, &elems, 0);
1081                                 
1082                                 if(elems.first) {
1083                                         
1084                                         nextkey(&elems, dir);
1085                                         
1086                                         /* copy to beziers */
1087                                         ik= elems.first;
1088                                         while(ik) {
1089                                                 for(a=0; a<OB_TOTIPO; a++) {
1090                                                         if(ik->data[a]) ik->data[a]->f1= ik->data[a]->f2= ik->data[a]->f3= ik->flag;
1091                                                 }
1092                                                 ik= ik->next;
1093                                         }
1094                                         
1095                                         free_ipokey(&elems);
1096                                 }
1097                         }
1098                 }
1099                 
1100                 base= base->next;
1101         }
1102         allqueue(REDRAWNLA, 0);
1103         allqueue(REDRAWACTION, 0);
1104         allqueue(REDRAWVIEW3D, 0);
1105         allspace(REMAKEIPO, 0);
1106         allqueue(REDRAWIPO, 0);
1107 }
1108
1109 int is_ipo_key_selected(Ipo *ipo)
1110 {
1111         int i;
1112         IpoCurve *icu;
1113         
1114         if (!ipo)
1115                 return 0;
1116         
1117         for (icu=ipo->curve.first; icu; icu=icu->next){
1118                 for (i=0; i<icu->totvert; i++)
1119                         if (BEZSELECTED(&icu->bezt[i]))
1120                                 return 1;
1121         }
1122         
1123         return 0;
1124 }
1125
1126 void set_ipo_key_selection(Ipo *ipo, int sel)
1127 {
1128         int i;
1129         IpoCurve *icu;
1130         
1131         if (!ipo)
1132                 return;
1133         
1134         for (icu=ipo->curve.first; icu; icu=icu->next){
1135                 for (i=0; i<icu->totvert; i++){
1136                         if (sel == 2) {
1137                                 icu->bezt[i].f1^=1;
1138                                 icu->bezt[i].f2^=1;
1139                                 icu->bezt[i].f3^=1;
1140                         }
1141                         else if (sel == 1){
1142                                 icu->bezt[i].f1|=1;
1143                                 icu->bezt[i].f2|=1;
1144                                 icu->bezt[i].f3|=1;
1145                         }
1146                         else{
1147                                 icu->bezt[i].f1&=~1;
1148                                 icu->bezt[i].f2&=~1;
1149                                 icu->bezt[i].f3&=~1;
1150                         }
1151                 }
1152         }
1153 }
1154
1155 int fullselect_ipo_keys(Ipo *ipo)
1156 {
1157         int i;
1158         IpoCurve *icu;
1159         int tvtot = 0;
1160         
1161         if (!ipo)
1162                 return tvtot;
1163         
1164         for (icu=ipo->curve.first; icu; icu=icu->next) {
1165                 for (i=0; i<icu->totvert; i++){
1166                         if (icu->bezt[i].f2 & 1){
1167                                 tvtot+=3;
1168                                 icu->bezt[i].f1 |= 1;
1169                                 icu->bezt[i].f3 |= 1;
1170                         }
1171                 }
1172         }
1173         
1174         return tvtot;
1175 }
1176
1177
1178 void borderselect_icu_key(IpoCurve *icu, float xmin, float xmax, 
1179                                                   int (*select_function)(BezTriple *))
1180 {
1181         /* Selects all bezier triples in the Ipocurve 
1182         * between times xmin and xmax, using the selection
1183         * function.
1184         */
1185         
1186         int i;
1187         
1188         /* loop through all of the bezier triples in
1189         * the Ipocurve -- if the triple occurs between
1190         * times xmin and xmax then select it using the selection
1191         * function
1192         */
1193         for (i=0; i<icu->totvert; i++){
1194                 if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] < xmax ){
1195                         select_function(&(icu->bezt[i]));
1196                 }
1197         }
1198 }
1199
1200 void borderselect_ipo_key(Ipo *ipo, float xmin, float xmax, int selectmode)
1201 {
1202         /* Selects all bezier triples in each Ipocurve of the
1203          * Ipo between times xmin and xmax, using the selection mode.
1204          */
1205         
1206         IpoCurve *icu;
1207         int (*select_function)(BezTriple *);
1208         
1209         /* If the ipo is no good then return */
1210         if (!ipo)
1211                 return;
1212         
1213         /* Set the selection function based on the
1214          * selection mode.
1215          */
1216         switch(selectmode) {
1217                 case SELECT_ADD:
1218                         select_function = select_bezier_add;
1219                         break;
1220                 case SELECT_SUBTRACT:
1221                         select_function = select_bezier_subtract;
1222                         break;
1223                 case SELECT_INVERT:
1224                         select_function = select_bezier_invert;
1225                         break;
1226                 default:
1227                         return;
1228         }
1229         
1230         /* loop through all of the bezier triples in all
1231                 * of the Ipocurves -- if the triple occurs between
1232                 * times xmin and xmax then select it using the selection
1233                 * function
1234                 */
1235         for (icu=ipo->curve.first; icu; icu=icu->next){
1236                 borderselect_icu_key(icu, xmin, xmax, select_function);
1237         }
1238 }
1239
1240 void select_ipo_key(Ipo *ipo, float selx, int selectmode)
1241 {
1242         /* Selects all bezier triples in each Ipocurve of the
1243         * Ipo at time selx, using the selection mode.
1244         */
1245         int i;
1246         IpoCurve *icu;
1247         int (*select_function)(BezTriple *);
1248         
1249         /* If the ipo is no good then return */
1250         if (!ipo)
1251                 return;
1252         
1253         /* Set the selection function based on the
1254                 * selection mode.
1255                 */
1256         switch(selectmode) {
1257                 case SELECT_ADD:
1258                         select_function = select_bezier_add;
1259                         break;
1260                 case SELECT_SUBTRACT:
1261                         select_function = select_bezier_subtract;
1262                         break;
1263                 case SELECT_INVERT:
1264                         select_function = select_bezier_invert;
1265                         break;
1266                 default:
1267                         return;
1268         }
1269         
1270         /* loop through all of the bezier triples in all
1271                 * of the Ipocurves -- if the triple occurs at
1272                 * time selx then select it using the selection
1273                 * function
1274                 */
1275         for (icu=ipo->curve.first; icu; icu=icu->next){
1276                 for (i=0; i<icu->totvert; i++){
1277                         if (icu->bezt[i].vec[1][0]==selx){
1278                                 select_function(&(icu->bezt[i]));
1279                         }
1280                 }
1281         }
1282 }
1283
1284 void select_icu_key(IpoCurve *icu, float selx, int selectmode)
1285 {
1286     /* Selects all bezier triples in the Ipocurve
1287         * at time selx, using the selection mode.
1288         * This is kind of sloppy the obvious similarities
1289         * with the above function, forgive me ...
1290         */
1291     int i;
1292     int (*select_function)(BezTriple *);
1293         
1294     /* If the icu is no good then return */
1295     if (!icu)
1296         return;
1297         
1298     /* Set the selection function based on the
1299                 * selection mode.
1300                 */
1301     switch(selectmode) {
1302                 case SELECT_ADD:
1303                         select_function = select_bezier_add;
1304                         break;
1305                 case SELECT_SUBTRACT:
1306                         select_function = select_bezier_subtract;
1307                         break;
1308                 case SELECT_INVERT:
1309                         select_function = select_bezier_invert;
1310                         break;
1311                 default:
1312                         return;
1313     }
1314         
1315     /* loop through all of the bezier triples in
1316                 * the Ipocurve -- if the triple occurs at
1317                 * time selx then select it using the selection
1318                 * function
1319                 */
1320     for (i=0; i<icu->totvert; i++){
1321         if (icu->bezt[i].vec[1][0]==selx){
1322             select_function(&(icu->bezt[i]));
1323         }
1324     }
1325 }
1326
1327 void set_exprap_ipo(int mode)
1328 {
1329         EditIpo *ei;
1330         int a;
1331         
1332         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1333         /* in case of keys: always ok */
1334         
1335         ei= G.sipo->editipo;
1336         for(a=0; a<G.sipo->totipo; a++, ei++) {
1337                 if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
1338                         if( (ei->flag & IPO_EDIT) || (ei->flag & IPO_SELECT) || (G.sipo->showkey) ) {
1339                                 ei->icu->extrap= mode;
1340                         }
1341                 }
1342         }
1343         
1344         editipo_changed(G.sipo, 1);
1345         BIF_undo_push("Set extrapolation Ipo");
1346 }