Fixed:
[blender.git] / source / blender / src / editipo.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
34 /* this code feels over-complex, mostly because I choose in the past to devise a system
35   that converts the Ipo blocks (linked to Object, Material, etc), into a copy of that
36   data which is being worked on;  the 'editipo'.
37   The editipo then can have 'ipokey' data, which is optimized for editing curves as if
38   it were key positions. This is still a great feature to work with, which makes ipo editing
39   in Blender still valuable. However, getting this beast under control was hard, even
40   for me... (ton) */
41
42 #include <stdlib.h>
43 #include <string.h>
44 #include <math.h>
45
46 #ifdef HAVE_CONFIG_H
47 #include <config.h>
48 #endif
49
50 #ifndef WIN32
51 #include <unistd.h>
52 #else
53 #include <io.h>
54 #include "BLI_winstuff.h"
55 #endif   
56 #include "MEM_guardedalloc.h"
57 #include "PIL_time.h"
58
59 #include "BLI_blenlib.h"
60 #include "BLI_arithb.h"
61
62 #include "DNA_constraint_types.h"
63 #include "DNA_action_types.h"
64 #include "DNA_armature_types.h"
65 #include "DNA_object_types.h"
66 #include "DNA_lamp_types.h"
67 #include "DNA_sequence_types.h"
68 #include "DNA_sound_types.h"
69 #include "DNA_camera_types.h"
70 #include "DNA_material_types.h"
71 #include "DNA_texture_types.h"
72 #include "DNA_key_types.h"
73 #include "DNA_screen_types.h"
74 #include "DNA_scene_types.h"
75 #include "DNA_ipo_types.h"
76 #include "DNA_curve_types.h"
77 #include "DNA_space_types.h"
78 #include "DNA_userdef_types.h"
79 #include "DNA_view3d_types.h"
80 #include "DNA_group_types.h"
81 #include "DNA_ika_types.h"
82
83 #include "BKE_utildefines.h"
84 #include "BKE_action.h"
85 #include "BKE_anim.h"
86 #include "BKE_material.h"
87 #include "BKE_texture.h"
88 #include "BKE_ipo.h"
89 #include "BKE_key.h"
90 #include "BKE_ika.h"
91 #include "BKE_displist.h"
92 #include "BKE_global.h"
93 #include "BKE_group.h"
94
95 #include "BIF_butspace.h"
96 #include "BIF_editkey.h"
97 #include "BIF_editseq.h"
98 #include "BIF_editview.h"
99 #include "BIF_interface.h"
100 #include "BIF_mywindow.h"
101 #include "BIF_poseobject.h"
102 #include "BIF_screen.h"
103 #include "BIF_space.h"
104 #include "BIF_toolbox.h"
105 #include "BIF_poseobject.h"
106
107 #include "BDR_drawobject.h"
108 #include "BDR_editobject.h"
109
110 #include "BSE_trans_types.h"
111 #include "BSE_editipo_types.h"
112 #include "BSE_drawipo.h"
113 #include "BSE_editipo.h"
114 #include "BSE_editaction.h"
115 #include "BSE_edit.h"
116 #include "BSE_drawview.h"
117 #include "BSE_headerbuttons.h"
118
119 #include "blendef.h"
120 #include "mydevice.h"
121 #include "render.h"
122
123 /* forwards */
124 #define BEZSELECTED(bezt)   (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1))
125
126 #define IPOTHRESH       0.9
127 #define ISPOIN(a, b, c)                       ( (a->b) && (a->c) )
128 #define ISPOIN3(a, b, c, d)           ( (a->b) && (a->c) && (a->d) )
129 #define ISPOIN4(a, b, c, d, e)        ( (a->b) && (a->c) && (a->d) && (a->e) )   
130
131 extern int ob_ar[];
132 extern int ma_ar[];
133 extern int seq_ar[];
134 extern int cu_ar[];
135 extern int key_ar[];
136 extern int wo_ar[];
137 extern int la_ar[];
138 extern int cam_ar[];
139 extern int snd_ar[];
140 extern int ac_ar[];
141 extern int co_ar[];
142 extern int te_ar[];
143
144 char *ob_ic_names[OB_TOTNAM] = { "LocX", "LocY", "LocZ", "dLocX", "dLocY", "dLocZ",
145                                                  "RotX", "RotY", "RotZ", "dRotX", "dRotY", "dRotZ",
146                                                  "SizeX", "SizeY", "SizeZ", "dSizeX", "dSizeY", "dSizeZ",
147                                                  "Layer", "Time", "ColR", "ColG", "ColB", "ColA",
148                                                  "FStreng", "FFall", "RDamp", "Damping", "Perm" };
149 char *obeff_ic_names[3] = { "EffX", "EffY", "EffZ" };
150 char *co_ic_names[CO_TOTNAM] = { "Inf" };
151 char *mtex_ic_names[TEX_TOTNAM] = { "OfsX", "OfsY", "OfsZ", "SizeX", "SizeY", "SizeZ",
152                                                   "texR", "texG", "texB", "DefVar", "Col", "Nor", "Var",
153                                                   "Disp" };
154 char *tex_ic_names[TE_TOTNAM] = { "NSize", "NDepth", "NType", "Turb", "Vnw1", "Vnw2",
155                                                                    "Vnw3", "Vnw4", "MinkMExp", "DistM", "ColT", "iScale",
156                                                                    "DistA", "MgType", "MgH", "Lacu", "Oct", "MgOff",
157                                                                    "MgGain", "NBase1", "NBase2" };
158 char *ma_ic_names[MA_TOTNAM] = { "R", "G", "B", "SpecR", "SpecG", "SpecB", "MirR",
159                                                  "MirG", "MirB", "Ref", "Alpha", "Emit", "Amb", "Spec",
160                                                  "Hard", "SpTra", "Ior", "Mode", "HaSize", "Translu",
161                                                  "RayMir", "FresMir", "FresMirI", "FresTra", "FresTraI",
162                                                  "TraGlow" };
163 char *seq_ic_names[SEQ_TOTNAM] = { "Fac" };
164 char *cu_ic_names[CU_TOTNAM] = { "Speed" };
165 char *key_ic_names[KEY_TOTNAM] = { "Speed", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5",
166                                                                         "Key 6", "Key 7", "Key 8", "Key 9", "Key 10",
167                                                                         "Key 11", "Key 12", "Key 13", "Key 14", "Key 15",
168                                                                         "Key 16", "Key 17", "Key 18", "Key 19", "Key 20",
169                                                                         "Key 21", "Key 22", "Key 23", "Key 24", "Key 25",
170                                                                         "Key 26", "Key 27", "Key 28", "Key 29", "Key 30",
171                                                                         "Key 31", "Key 32", "Key 33", "Key 34", "Key 35",
172                                                                         "Key 36", "Key 37", "Key 38", "Key 39", "Key 40",
173                                                                         "Key 41", "Key 42", "Key 43", "Key 44", "Key 45",
174                                                                         "Key 46", "Key 47", "Key 48", "Key 49", "Key 50",
175                                                                         "Key 51", "Key 52", "Key 53", "Key 54", "Key 55",
176                                                                         "Key 56", "Key 57", "Key 58", "Key 59", "Key 60",
177                                                                         "Key 61", "Key 62", "Key 63"};
178 char *wo_ic_names[WO_TOTNAM] = { "HorR", "HorG", "HorB", "ZenR", "ZenG", "ZenB", "Expos",
179                                                  "Misi", "MisDi", "MisSta", "MisHi", "StarR", "StarB",
180                                                  "StarG", "StarDi", "StarSi" };
181 char *la_ic_names[LA_TOTNAM] = { "Energ", "R", "G", "B", "Dist", "SpoSi", "SpoBl",
182                                                                   "Quad1", "Quad2", "HaInt" };
183 /* yafray: two curve names added, 'Apert' for aperture, and 'FDist' for focal distance */
184 char *cam_ic_names[CAM_TOTNAM] = { "Lens", "ClSta", "ClEnd", "Apert", "FDist" };
185 char *snd_ic_names[SND_TOTNAM] = { "Vol", "Pitch", "Pan", "Atten" };
186 char *ac_ic_names[AC_TOTNAM] = {"LocX", "LocY", "LocZ", "SizeX", "SizeY",
187                                                   "SizeZ", "QuatW", "QuatX", "QuatY", "QuatZ"};
188 char *ic_name_empty[1] ={ "" };
189
190 char *getname_ac_ei(int nr) {
191         switch(nr) {
192         case AC_LOC_X:
193         case AC_LOC_Y:
194         case AC_LOC_Z:
195                 return ac_ic_names[nr-1];
196         case AC_SIZE_X:
197         case AC_SIZE_Y:
198         case AC_SIZE_Z:
199                 return ac_ic_names[nr-10];
200         case AC_QUAT_X:
201         case AC_QUAT_Y:
202         case AC_QUAT_Z:
203         case AC_QUAT_W:
204                 return ac_ic_names[nr-19];
205         default:
206                 return ic_name_empty[0]; /* empty */
207         }
208 }
209
210 char *getname_co_ei(int nr)
211 {
212         switch(nr){
213         case CO_ENFORCE:
214                 return co_ic_names[nr-1];
215         }
216         return ic_name_empty[0];
217 }
218
219 char *getname_ob_ei(int nr, int colipo)
220 {
221         if(!colipo && (nr>=OB_EFF_X && nr <=OB_EFF_Z)) {
222                 return obeff_ic_names[nr-OB_EFF_X];
223         } else {
224                 if(nr>=OB_LOC_X && nr <= OB_PD_PERM) return ob_ic_names[nr-1];
225         }
226         return ic_name_empty[0];
227 }
228
229 char *getname_tex_ei(int nr)
230 {
231         if(nr>=TE_NSIZE && nr<=TE_N_BAS2) return tex_ic_names[nr-1];
232
233         return ic_name_empty[0];
234 }
235
236 char *getname_mtex_ei(int nr)
237 {
238         if(nr>=MAP_OFS_X && nr<=MAP_DISP) return mtex_ic_names[nr-1];
239         
240         return ic_name_empty[0];
241 }
242
243 char *getname_mat_ei(int nr)
244 {
245         if(nr>=MA_MAP1) return getname_mtex_ei((nr & (MA_MAP1-1)));
246         else {
247                 if(nr>=MA_COL_R && nr<=MA_ADD) return ma_ic_names[nr-1];
248         }
249         return ic_name_empty[0];
250 }
251
252 char *getname_world_ei(int nr)
253 {
254         if(nr>=MA_MAP1) return getname_mtex_ei((nr & (MA_MAP1-1)));
255         else {
256                 if(nr>=WO_HOR_R && nr<=WO_STARSIZE) return wo_ic_names[nr-1];
257         }
258         return ic_name_empty[0];
259 }
260
261 char *getname_seq_ei(int nr)
262 {
263         if(nr == SEQ_FAC1) return seq_ic_names[nr-1];
264         return ic_name_empty[0];
265 }
266
267 char *getname_cu_ei(int nr)
268 {
269         if(nr==CU_SPEED) return cu_ic_names[nr-1];
270         return ic_name_empty[0];
271 }
272
273 char *getname_key_ei(int nr)
274 {
275         if(nr>=KEY_SPEED && nr<KEY_TOTNAM) return key_ic_names[nr];
276         return ic_name_empty[0];
277 }
278
279 char *getname_la_ei(int nr)
280 {
281         if(nr>=MA_MAP1) return getname_mtex_ei((nr & (MA_MAP1-1)));
282         else {
283                 if(nr>=LA_ENERGY && nr<=LA_HALOINT) return la_ic_names[nr-1];
284         }
285         return ic_name_empty[0];
286 }
287
288 char *getname_cam_ei(int nr)
289 {
290         /* yafray: curves extended to CAM_YF_FDIST */
291         //if(nr>=CAM_LENS && nr<=CAM_END) return cam_ic_names[nr-1];
292         if(nr>=CAM_LENS && nr<=CAM_YF_FDIST) return cam_ic_names[nr-1];
293         return ic_name_empty[0];
294 }
295
296 char *getname_snd_ei(int nr)
297 {
298         if(nr>=SND_VOLUME && nr<=SND_ATTEN) return snd_ic_names[nr-1];
299         return ic_name_empty[0];
300 }
301
302 IpoCurve *find_ipocurve(Ipo *ipo, int adrcode)
303 {
304         if(ipo) {
305                 IpoCurve *icu= ipo->curve.first;
306                 while(icu) {
307                         if(icu->adrcode==adrcode) return icu;
308                         icu= icu->next;
309                 }
310         }
311         return NULL;
312 }
313
314 void boundbox_ipocurve(IpoCurve *icu)
315 {
316         BezTriple *bezt;
317         float vec[3]={0.0,0.0,0.0};
318         float min[3], max[3];
319         int a;
320         
321         if(icu->totvert) {
322                 INIT_MINMAX(min, max);
323                 
324                 if(icu->bezt ) {
325                         a= icu->totvert;
326                         bezt= icu->bezt;
327                         while(a--) {
328                                 if(icu->vartype & IPO_BITS) {
329                                         vec[0]= bezt->vec[1][0];
330                                         vec[1]= 0.0;
331                                         DO_MINMAX(vec, min, max);
332                                         
333                                         vec[1]= 16.0;
334                                         DO_MINMAX(vec, min, max);
335                                 }
336                                 else {
337                                         if(icu->ipo==IPO_BEZ && a!=icu->totvert-1) {
338                                                 DO_MINMAX(bezt->vec[0], min, max);
339                                         }
340                                         DO_MINMAX(bezt->vec[1], min, max);
341                                         if(icu->ipo==IPO_BEZ && a!=0) {
342                                                 DO_MINMAX(bezt->vec[2], min, max);
343                                         }
344                                 }
345                                 
346                                 bezt++;
347                         }
348                 }
349                 if(min[0]==max[0]) max[0]= (float)(min[0]+1.0);
350                 if(min[1]==max[1]) max[1]= (float)(min[1]+0.1);
351                 
352                 icu->totrct.xmin= min[0];
353                 icu->totrct.ymin= min[1];
354                 icu->totrct.xmax= max[0];
355                 icu->totrct.ymax= max[1];
356         }
357         else {
358                 icu->totrct.xmin= icu->totrct.ymin= 0.0;
359                 icu->totrct.xmax= EFRA;
360                 icu->totrct.ymax= 1.0;
361         }
362 }
363
364 void boundbox_ipo(Ipo *ipo, rctf *bb)
365 {
366         IpoCurve *icu;
367         int first= 1;
368         
369         icu= ipo->curve.first;
370         while(icu) {
371                         
372                 boundbox_ipocurve(icu);
373                                 
374                 if(first) {
375                         *bb= icu->totrct;
376                         first= 0;
377                 }
378                 else BLI_union_rctf(bb, &(icu->totrct));
379                 
380                 icu= icu->next;
381         }
382 }
383
384
385
386 void editipo_changed(SpaceIpo *si, int doredraw)
387 {
388         EditIpo *ei;
389         View2D *v2d;
390         Key *key;
391         KeyBlock *kb;
392         int a, first=1;
393
394         ei= si->editipo;
395         if(ei==0)
396                 return;
397         
398
399         for(a=0; a<si->totipo; a++, ei++) {
400                 
401                 if(ei->icu) {
402                         
403                                 /* twice because of ittererating new autohandle */
404                         calchandles_ipocurve(ei->icu);
405                         calchandles_ipocurve(ei->icu);
406                         
407                         if(ei->flag & IPO_VISIBLE) {
408                 
409                                 boundbox_ipocurve(ei->icu);
410                                 sort_time_ipocurve(ei->icu);
411                                 if(first) {
412                                         si->v2d.tot= ei->icu->totrct;
413                                         first= 0;
414                                 }
415                                 else BLI_union_rctf(&(si->v2d.tot), &(ei->icu->totrct));
416                         }
417                 }
418         }
419         
420
421         v2d= &(si->v2d);        
422
423         /* keylines? */
424         if(si->blocktype==ID_KE) {
425                 key= (Key *)si->from;
426                 if(key && key->block.first) {
427                         kb= key->block.first;
428                         if(kb->pos < v2d->tot.ymin) v2d->tot.ymin= kb->pos;
429                         kb= key->block.last;
430                         if(kb->pos > v2d->tot.ymax) v2d->tot.ymax= kb->pos;
431                 }
432         }
433         
434         /* is there no curve? */
435         if(first) {
436                 v2d->tot.xmin= 0.0;
437                 v2d->tot.xmax= EFRA;
438                 v2d->tot.ymin= (float)-0.1;
439                 v2d->tot.ymax= (float)1.1;
440         
441                 if(si->blocktype==ID_SEQ) {
442                         v2d->tot.xmin= -5.0;
443                         v2d->tot.xmax= 105.0;
444                         v2d->tot.ymin= (float)-0.1;
445                         v2d->tot.ymax= (float)1.1;
446                 }
447         }
448         
449         si->tot= v2d->tot;      
450         
451         if(doredraw) {
452                 /* if you always call do_ipo: you get problems with insertkey, for example
453                  * when inserting only a 'loc' the 'ob->rot' value then is changed.
454                  */
455
456                 if(si->blocktype==ID_OB) {                      
457                                 /* clear delta loc,rot,size (when free/delete ipo) */
458                         clear_delta_obipo(si->ipo);
459                         
460                 }
461         
462                 do_ipo(si->ipo);
463
464                 allqueue(REDRAWIPO, 0);
465                 allqueue (REDRAWACTION, 0);
466                 allqueue(REDRAWNLA, 0);
467                 allqueue(REDRAWBUTSOBJECT, 0);
468                 
469                 if(si->blocktype==ID_OB) {
470                         Object *ob= (Object *)si->from;                 
471                         if(ob && ob->type==OB_IKA) itterate_ika(ob);
472                         allqueue(REDRAWVIEW3D, 0);
473                         allqueue(REDRAWNLA, 0);
474                 }
475
476                 else if(si->blocktype==ID_MA) allqueue(REDRAWBUTSSHADING, 0);
477                 else if(si->blocktype==ID_TE) allqueue(REDRAWBUTSSHADING, 0);
478                 else if(si->blocktype==ID_WO) allqueue(REDRAWBUTSSHADING, 0);
479                 else if(si->blocktype==ID_LA) allqueue(REDRAWBUTSSHADING, 0);
480 //              else if(si->blocktype==ID_SO) allqueue(REDRAWBUTSSOUND, 0);
481                 else if(si->blocktype==ID_CA) {
482                         allqueue(REDRAWBUTSEDIT, 0);
483                         allqueue(REDRAWVIEW3D, 0);
484                 }
485                 else if(si->blocktype==ID_SEQ) clear_last_seq();
486                 else if(si->blocktype==ID_AC){
487                         do_all_actions();
488                         allqueue(REDRAWACTION, 0);
489                         allqueue(REDRAWNLA, 0);
490                 }
491                 else if(si->blocktype==ID_KE) {
492                         do_spec_key((Key *)si->from);
493                         allqueue(REDRAWVIEW3D, 0);
494                 }
495                 else if(si->blocktype==ID_CU) {
496                         calc_curvepath(OBACT);
497                         allqueue(REDRAWVIEW3D, 0);
498                 }
499         }
500
501         if(si->showkey) make_ipokey();
502 }
503
504 void scale_editipo()
505 {
506         /* comes from buttons, scale with G.sipo->tot rect */
507         
508         EditIpo *ei;
509         BezTriple *bezt;
510         float facx, facy;
511         int a, b;       
512         
513         facx= (G.sipo->tot.xmax-G.sipo->tot.xmin)/(G.sipo->v2d.tot.xmax-G.sipo->v2d.tot.xmin);
514         facy= (G.sipo->tot.ymax-G.sipo->tot.ymin)/(G.sipo->v2d.tot.ymax-G.sipo->v2d.tot.ymin);
515
516         ei= G.sipo->editipo;
517         if(ei==0) return;
518         for(a=0; a<G.sipo->totipo; a++, ei++) {
519                 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
520                         bezt= ei->icu->bezt;
521                         b= ei->icu->totvert;
522                         while(b--) {
523                                 
524                                 bezt->vec[0][0]= facx*(bezt->vec[0][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
525                                 bezt->vec[1][0]= facx*(bezt->vec[1][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
526                                 bezt->vec[2][0]= facx*(bezt->vec[2][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
527                         
528                                 bezt->vec[0][1]= facy*(bezt->vec[0][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
529                                 bezt->vec[1][1]= facy*(bezt->vec[1][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
530                                 bezt->vec[2][1]= facy*(bezt->vec[2][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
531
532                                 bezt++;
533                         }
534                 }
535         }
536
537         editipo_changed(G.sipo, 1);
538
539         BIF_undo_push("Scale Edit Ipo");
540         allqueue(REDRAWNLA, 0);
541         allqueue (REDRAWACTION, 0);
542         allqueue(REDRAWIPO, 0);
543 }
544
545
546 Ipo *get_ipo_to_edit(ID **from)
547 {
548         Object *ob= OBACT;
549         
550         *from= 0;
551         
552         
553         if (G.sipo->pin) {
554                 *from = G.sipo->from;
555                 return G.sipo->ipo;
556         }
557
558         if(G.sipo->blocktype==ID_SEQ) {
559                 extern Sequence *last_seq;
560                 
561                 *from= (ID *)last_seq;
562                 if(last_seq) return last_seq->ipo;
563         }
564         else if(G.sipo->blocktype==IPO_CO){
565                 if (ob && ob->activecon){
566                         *from= (ID*) ob;
567                         return ob->activecon->ipo;
568                 }
569         }
570         else if(G.sipo->blocktype==ID_AC) {
571                 bActionChannel *chan;
572                 if (ob && ob->action){
573                         *from= (ID *) ob->action;
574                         chan= get_hilighted_action_channel(ob->action);
575                         if (chan)
576                                 return chan->ipo;
577                         else{
578                                 *from = NULL;
579                                 return NULL;
580                         }
581                 }
582
583         }
584         else if(G.sipo->blocktype==ID_WO) {
585                 World *wo= G.scene->world;
586                 *from= (ID *)wo;
587                 if(wo) return wo->ipo;
588         }
589         else if(G.sipo->blocktype==ID_OB) {
590                 if(ob) {
591                         *from= (ID *)ob;
592                         return ob->ipo;
593                 }
594         }
595         else if(G.sipo->blocktype==ID_TE) {
596                 if(ob) {
597                         Tex *tex= give_current_texture(ob, ob->actcol);
598                         *from= (ID *)tex;
599                         if(tex) return tex->ipo;
600                 }
601         }
602         else if(G.sipo->blocktype==ID_MA) {
603                 if(ob) {
604                         Material *ma= give_current_material(ob, ob->actcol);
605                         *from= (ID *)ma;
606                         if(ma) return ma->ipo;
607                 }
608         }
609         else if(G.sipo->blocktype==ID_KE) {
610                 if(ob) {
611                         Key *key= give_current_key(ob);
612                         *from= (ID *)key;
613                         if(key) return key->ipo;
614                 }
615         }
616         else if(G.sipo->blocktype==ID_CU) {
617                 if(ob && ob->type==OB_CURVE) {
618                         Curve *cu= ob->data;
619                         *from= (ID *)cu;
620                         return cu->ipo;
621                 }
622         }
623         else if(G.sipo->blocktype==ID_LA) {
624                 if(ob && ob->type==OB_LAMP) {
625                         Lamp *la= ob->data;
626                         *from= (ID *)la;
627                         return la->ipo;
628                 }
629         }
630         else if(G.sipo->blocktype==ID_CA) {
631                 if(ob && ob->type==OB_CAMERA) {
632                         Camera *ca= ob->data;
633                         *from= (ID *)ca;
634                         if(ca) return ca->ipo;
635                 }
636         }
637         else if(G.sipo->blocktype==ID_SO) {
638
639 //              if (G.buts && G.buts->mainb == BUTS_SOUND) {
640 //                      bSound *sound = G.buts->lockpoin;
641 //                      *from= (ID *)sound;
642 //                      if(sound) return sound->ipo;
643 //              }
644         }
645
646         return NULL;
647 }
648
649 unsigned int ipo_rainbow(int cur, int tot)
650 {
651         float dfac, fac, sat;
652
653         dfac= (float)(1.0/( (float)tot+1.0));
654
655         /* this calculation makes 2 different cycles of rainbow colors */
656         if(cur< tot/2) fac= (float)(cur*2.0*dfac);
657         else fac= (float)((cur-tot/2)*2.0*dfac +dfac);
658         
659         if(fac>0.5 && fac<0.8) sat= (float)0.4;
660         else sat= 0.5;
661         
662         return hsv_to_cpack(fac, sat, 1.0);
663 }               
664
665 void make_ob_editipo(Object *ob, SpaceIpo *si)
666 {
667         EditIpo *ei;
668         int a, len, colipo=0;
669         char *name;
670         
671         if(ob->type==OB_MESH) colipo= 1;
672
673         ei= si->editipo= MEM_callocN(OB_TOTIPO*sizeof(EditIpo), "editipo");
674         
675         si->totipo= OB_TOTIPO;
676         
677         for(a=0; a<OB_TOTIPO; a++) {
678                 name = getname_ob_ei(ob_ar[a], colipo);
679                 strcpy(ei->name, name);
680                 ei->adrcode= ob_ar[a];
681                 
682                 if ELEM6(ei->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z, OB_DROT_X, OB_DROT_Y, OB_DROT_Z) ei->disptype= IPO_DISPDEGR;
683                 else if(ei->adrcode==OB_LAY) ei->disptype= IPO_DISPBITS;
684                 else if(ei->adrcode==OB_TIME) ei->disptype= IPO_DISPTIME;
685
686                 ei->col= ipo_rainbow(a, OB_TOTIPO);
687
688                 if(colipo) {
689                         len= strlen(ei->name);
690                         if(len) {
691                                 if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
692                                 else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
693                                 else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
694                         }
695                 }
696                 
697                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
698                 if(ei->icu) {
699                         ei->flag= ei->icu->flag;
700                 }
701                 
702                 ei++;
703         }
704 }
705
706
707 void make_seq_editipo(SpaceIpo *si)
708 {
709         EditIpo *ei;
710         int a;
711         char *name;
712         
713         ei= si->editipo= MEM_callocN(SEQ_TOTIPO*sizeof(EditIpo), "editipo");
714         
715         si->totipo= SEQ_TOTIPO;
716         
717         
718         for(a=0; a<SEQ_TOTIPO; a++) {
719                 name = getname_seq_ei(seq_ar[a]);
720                 strcpy(ei->name, name);
721                 ei->adrcode= seq_ar[a];
722                 
723                 ei->col= ipo_rainbow(a, SEQ_TOTIPO);
724                 
725                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
726                 if(ei->icu) {
727                         ei->flag= ei->icu->flag;
728                 }
729                 else ei->flag |= IPO_VISIBLE;
730                 
731                 ei++;
732         }
733 }
734
735 void make_cu_editipo(SpaceIpo *si)
736 {
737         EditIpo *ei;
738         int a;
739         char *name;
740         
741         ei= si->editipo= MEM_callocN(CU_TOTIPO*sizeof(EditIpo), "editipo");
742         
743         si->totipo= CU_TOTIPO;
744         
745         
746         for(a=0; a<CU_TOTIPO; a++) {
747                 name = getname_cu_ei(cu_ar[a]);
748                 strcpy(ei->name, name);
749                 ei->adrcode= cu_ar[a];
750                 
751                 ei->col= ipo_rainbow(a, CU_TOTIPO);
752                 
753                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
754                 if(ei->icu) {
755                         ei->flag= ei->icu->flag;
756                 }
757                 else ei->flag |= IPO_VISIBLE;
758                  
759                 ei++;
760         }
761 }
762
763 void make_key_editipo(SpaceIpo *si)
764 {
765         Key *key;
766         KeyBlock *kb=NULL;
767         EditIpo *ei;
768         int a;
769         char *name;
770         
771         ei= si->editipo= MEM_callocN(KEY_TOTIPO*sizeof(EditIpo), "editipo");
772         
773         si->totipo= KEY_TOTIPO;
774         
775         key= (Key *)G.sipo->from;
776         if(key) kb= key->block.first;
777         
778         for(a=0; a<KEY_TOTIPO; a++, ei++) {
779                 if(kb && kb->name[0] != 0) strncpy(ei->name, kb->name, 32);     // length both same
780                 else {
781                         name = getname_key_ei(key_ar[a]);
782                         strcpy(ei->name, name);
783                 }
784                 ei->adrcode= key_ar[a];
785                 
786                 ei->col= ipo_rainbow(a, KEY_TOTIPO);
787                 
788                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
789                 if(ei->icu) {
790                         ei->flag= ei->icu->flag;
791                 }
792                 else if(a==0) ei->flag |= IPO_VISIBLE;
793                  
794                 if(kb) kb= kb->next;
795         }
796         
797         ei= si->editipo;
798         if(key && key->type==KEY_RELATIVE) {
799                 strcpy(ei->name, "----");
800         }
801         else {
802                 ei->flag |= IPO_VISIBLE;
803         }
804 }
805
806 int texchannel_to_adrcode(int channel)
807 {
808         switch(channel) {
809                 case 0: return MA_MAP1;
810                 case 1: return MA_MAP2; 
811                 case 2: return MA_MAP3; 
812                 case 3: return MA_MAP4; 
813                 case 4: return MA_MAP5; 
814                 case 5: return MA_MAP6; 
815                 case 6: return MA_MAP7; 
816                 case 7: return MA_MAP8; 
817                 default: return 0;
818         }
819 }
820
821 void make_mat_editipo(SpaceIpo *si)
822 {
823         EditIpo *ei;
824         int a, len;
825         char *name;
826         
827         if(si->from==0) return;
828         
829         ei= si->editipo= MEM_callocN(MA_TOTIPO*sizeof(EditIpo), "editipo");
830         
831         si->totipo= MA_TOTIPO;
832         
833         for(a=0; a<MA_TOTIPO; a++) {
834                 name = getname_mat_ei(ma_ar[a]);
835                 strcpy(ei->name, name);
836                 ei->adrcode= ma_ar[a];
837                 
838                 if(ei->adrcode & MA_MAP1) {
839                         ei->adrcode-= MA_MAP1;
840                         ei->adrcode |= texchannel_to_adrcode(si->channel);
841                 }
842                 else {
843                         if(ei->adrcode==MA_MODE) ei->disptype= IPO_DISPBITS;
844                 }
845                 
846                 ei->col= ipo_rainbow(a, MA_TOTIPO);
847                 
848                 len= strlen(ei->name);
849                 if(len) {
850                         if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
851                         else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
852                         else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
853                 }
854                 
855                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
856                 if(ei->icu) {
857                         ei->flag= ei->icu->flag;
858                 }
859                 
860                 ei++;
861         }
862 }
863
864 void make_texture_editipo(SpaceIpo *si)
865 {
866         EditIpo *ei;
867         int a;
868         char *name;
869         
870         if(si->from==0) return;    
871         
872         ei= si->editipo= MEM_callocN(TE_TOTIPO*sizeof(EditIpo), "editipo");
873         
874         si->totipo= TE_TOTIPO;
875         
876         for(a=0; a<TE_TOTIPO; a++) {
877                 name = getname_tex_ei(te_ar[a]);
878                 strcpy(ei->name, name);
879                         ei->adrcode= te_ar[a];
880
881                 ei->col= ipo_rainbow(a, TE_TOTIPO);
882                 
883                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
884                 if(ei->icu) {
885                         ei->flag= ei->icu->flag;
886                 }
887                 
888                 ei++;
889         }
890 }
891
892 void make_world_editipo(SpaceIpo *si)
893 {
894         EditIpo *ei;
895         int a, len;
896         char *name;
897         
898         if(si->from==0) return;
899         
900         ei= si->editipo= MEM_callocN(WO_TOTIPO*sizeof(EditIpo), "editipo");
901         
902         si->totipo= WO_TOTIPO;
903         
904         for(a=0; a<WO_TOTIPO; a++) {
905                 name = getname_world_ei(wo_ar[a]);
906                 
907                 strcpy(ei->name, name); 
908                 ei->adrcode= wo_ar[a];
909                 
910                 if(ei->adrcode & MA_MAP1) {
911                         ei->adrcode-= MA_MAP1;
912                         ei->adrcode |= texchannel_to_adrcode(si->channel);
913                 }
914                 else {
915                         if(ei->adrcode==MA_MODE) ei->disptype= IPO_DISPBITS;
916                 }
917                 
918                 ei->col= ipo_rainbow(a, WO_TOTIPO);
919                 
920                 len= strlen(ei->name);
921                 if(len) {
922                         if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
923                         else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
924                         else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
925                 }
926                 
927                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
928                 if(ei->icu) {
929                         ei->flag= ei->icu->flag;
930                 }
931                 
932                 ei++;
933         }
934 }
935
936 void make_lamp_editipo(SpaceIpo *si)
937 {
938         EditIpo *ei;
939         int a;
940         char *name;
941         
942         ei= si->editipo= MEM_callocN(LA_TOTIPO*sizeof(EditIpo), "editipo");
943         
944         si->totipo= LA_TOTIPO;
945         
946         
947         for(a=0; a<LA_TOTIPO; a++) {
948                 name = getname_la_ei(la_ar[a]);
949                 strcpy(ei->name, name);
950                 ei->adrcode= la_ar[a];
951
952                 if(ei->adrcode & MA_MAP1) {
953                         ei->adrcode-= MA_MAP1;
954                         ei->adrcode |= texchannel_to_adrcode(si->channel);
955                 }
956
957                 ei->col= ipo_rainbow(a, LA_TOTIPO);
958                 
959                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
960                 if(ei->icu) {
961                         ei->flag= ei->icu->flag;
962                 }
963                 
964                 ei++;
965         }
966 }
967
968 void make_camera_editipo(SpaceIpo *si)
969 {
970         EditIpo *ei;
971         int a;
972         char *name;
973         
974         ei= si->editipo= MEM_callocN(CAM_TOTIPO*sizeof(EditIpo), "editipo");
975         
976         si->totipo= CAM_TOTIPO;
977         
978         
979         for(a=0; a<CAM_TOTIPO; a++) {
980                 name = getname_cam_ei(cam_ar[a]);
981                 strcpy(ei->name, name);
982                 ei->adrcode= cam_ar[a];
983
984                 ei->col= ipo_rainbow(a, CAM_TOTIPO);
985                 
986                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
987                 if(ei->icu) {
988                         ei->flag= ei->icu->flag;
989                 }
990                 
991                 ei++;
992         }
993 }
994
995 int make_constraint_editipo(Ipo *ipo, EditIpo **si)
996 {
997         EditIpo *ei;
998         int a;
999         char *name;
1000         
1001         ei= *si= MEM_callocN(CO_TOTIPO*sizeof(EditIpo), "editipo");
1002         
1003         for(a=0; a<CO_TOTIPO; a++) {
1004                 name = getname_co_ei(co_ar[a]);
1005                 strcpy(ei->name, name);
1006                 ei->adrcode= co_ar[a];
1007
1008                 ei->col= ipo_rainbow(a, CO_TOTIPO);
1009                 
1010                 ei->icu= find_ipocurve(ipo, ei->adrcode);
1011                 if(ei->icu) {
1012                         ei->flag= ei->icu->flag;
1013                 }
1014                 
1015                 ei++;
1016         }
1017
1018         return CO_TOTIPO;
1019 }
1020 int make_action_editipo(Ipo *ipo, EditIpo **si)
1021 {
1022         EditIpo *ei;
1023         int a;
1024         char *name;
1025         
1026         ei= *si= MEM_callocN(AC_TOTIPO*sizeof(EditIpo), "editipo");
1027         
1028         for(a=0; a<AC_TOTIPO; a++) {
1029                 name = getname_ac_ei(ac_ar[a]);
1030                 strcpy(ei->name, name);
1031                 ei->adrcode= ac_ar[a];
1032
1033                 ei->col= ipo_rainbow(a, AC_TOTIPO);
1034                 
1035                 ei->icu= find_ipocurve(ipo, ei->adrcode);
1036                 if(ei->icu) {
1037                         ei->flag= ei->icu->flag;
1038                 }
1039                 
1040                 ei++;
1041         }
1042
1043         return AC_TOTIPO;
1044 }
1045
1046 void make_sound_editipo(SpaceIpo *si)
1047 {
1048         EditIpo *ei;
1049         int a;
1050         char *name;
1051         
1052         ei= si->editipo= MEM_callocN(SND_TOTIPO*sizeof(EditIpo), "editipo");
1053         
1054         si->totipo= SND_TOTIPO;
1055         
1056         
1057         for(a=0; a<SND_TOTIPO; a++) {
1058                 name = getname_snd_ei(snd_ar[a]);
1059                 strcpy(ei->name, name);
1060                 ei->adrcode= snd_ar[a];
1061
1062                 ei->col= ipo_rainbow(a, SND_TOTIPO);
1063                 
1064                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
1065                 if(ei->icu) {
1066                         ei->flag= ei->icu->flag;
1067                 }
1068                 
1069                 ei++;
1070         }
1071 }
1072
1073 void make_editipo()
1074 {
1075         EditIpo *ei;
1076         Object *ob;
1077         ID *from;
1078         rctf *rf;
1079         int a;
1080
1081         if(G.sipo->editipo)
1082                 MEM_freeN(G.sipo->editipo);
1083         G.sipo->editipo= 0;
1084         G.sipo->totipo= 0;
1085         ob= OBACT;
1086
1087         G.sipo->ipo= get_ipo_to_edit(&from);
1088         G.sipo->from= from;
1089
1090         if(G.sipo->ipo) G.sipo->showkey= G.sipo->ipo->showkey;
1091
1092         if(G.sipo->blocktype==ID_SEQ) {
1093                 make_seq_editipo(G.sipo);
1094         }
1095         else if(G.sipo->blocktype==ID_WO) {
1096                 make_world_editipo(G.sipo);
1097         } 
1098         else if(G.sipo->blocktype==ID_OB) {
1099                 if (ob) {
1100                         ob->ipowin= ID_OB;
1101                         make_ob_editipo(ob, G.sipo);
1102                 }
1103         }
1104         else if(G.sipo->blocktype==ID_MA) {
1105                 if (ob) {
1106                         ob->ipowin= ID_MA;
1107                         make_mat_editipo(G.sipo);
1108                 }
1109         }
1110         else if(G.sipo->blocktype==ID_CU) {
1111                 if (ob) {
1112                         ob->ipowin= ID_CU;
1113                         make_cu_editipo(G.sipo);
1114                 }
1115         }
1116         else if(G.sipo->blocktype==ID_KE) {
1117                 if (ob) {
1118                         ob->ipowin= ID_KE;
1119                         make_key_editipo(G.sipo);
1120                 }
1121         }
1122         else if(G.sipo->blocktype==ID_LA) {
1123                 if (ob) {
1124                         ob->ipowin= ID_LA;
1125                         make_lamp_editipo(G.sipo);
1126                 }
1127         }
1128         else if(G.sipo->blocktype==ID_TE) {
1129                 if (ob) {
1130                         ob->ipowin= ID_TE;
1131                         make_texture_editipo(G.sipo);
1132                 }
1133         }
1134         else if(G.sipo->blocktype==ID_CA) {
1135                 if (ob) {
1136                         ob->ipowin= ID_CA;
1137                         make_camera_editipo(G.sipo);
1138                 }
1139         }
1140         else if(G.sipo->blocktype==ID_SO) {
1141                 if (ob) {
1142                         ob->ipowin= ID_SO;
1143                         make_sound_editipo(G.sipo);
1144                 }
1145         }
1146         else if(G.sipo->blocktype==IPO_CO){
1147                 G.sipo->totipo = make_constraint_editipo(G.sipo->ipo, (EditIpo**)&G.sipo->editipo);
1148                 if (ob) {
1149                         ob->ipowin= IPO_CO;
1150                 }
1151         }
1152         else if(G.sipo->blocktype==ID_AC) {
1153
1154                 G.sipo->totipo = make_action_editipo(G.sipo->ipo, (EditIpo**)&G.sipo->editipo);
1155                 if (ob) {
1156                         ob->ipowin= ID_AC;
1157                 }
1158         }
1159
1160         if(G.sipo->editipo==0) return;
1161         
1162         ei= G.sipo->editipo;
1163         for(a=0; a<G.sipo->totipo; a++, ei++) {
1164                 
1165                 if(ei->flag & IPO_VISIBLE) ei->flag |= (1<<IPO_IS_SELECTED);
1166                 
1167                 if(ei->icu) ei->icu->flag= ei->flag;
1168         }
1169         editipo_changed(G.sipo, 0);
1170         
1171         if(G.sipo->ipo) {
1172
1173                 if (G.sipo->pin)
1174                         rf= &(G.sipo->v2d.cur);
1175                 else
1176                         rf= &(G.sipo->ipo->cur);
1177                 
1178                 if(rf->xmin<rf->xmax && rf->ymin<rf->ymax) G.v2d->cur= *rf;
1179                 
1180         }
1181         else {
1182                 if(G.sipo->blocktype==ID_OB) {
1183                         G.v2d->cur.xmin= 0.0;
1184                         G.v2d->cur.xmax= EFRA;
1185                         G.v2d->cur.ymin= -5.0;
1186                         G.v2d->cur.ymax= +5.0;
1187                 }
1188                 else if(G.sipo->blocktype==ID_CA) {
1189                         G.v2d->cur.xmin= 0.0;
1190                         G.v2d->cur.xmax= EFRA;
1191                         G.v2d->cur.ymin= 0.0;
1192                         G.v2d->cur.ymax= 100.0;
1193                 }
1194                 else if ELEM5(G.sipo->blocktype, ID_MA, ID_CU, ID_WO, ID_LA, IPO_CO) {
1195                         G.v2d->cur.xmin= (float)-0.1;
1196                         G.v2d->cur.xmax= EFRA;
1197                         G.v2d->cur.ymin= (float)-0.1;
1198                         G.v2d->cur.ymax= (float)+1.1;
1199                 }
1200                 else if(G.sipo->blocktype==ID_TE) {
1201                         G.v2d->cur.xmin= (float)-0.1;
1202                         G.v2d->cur.xmax= EFRA;
1203                         G.v2d->cur.ymin= (float)-0.1;
1204                         G.v2d->cur.ymax= (float)+1.1;
1205                 }
1206                 else if(G.sipo->blocktype==ID_SEQ) {
1207                         G.v2d->cur.xmin= -5.0;
1208                         G.v2d->cur.xmax= 105.0;
1209                         G.v2d->cur.ymin= (float)-0.1;
1210                         G.v2d->cur.ymax= (float)+1.1;
1211                 }
1212                 else if(G.sipo->blocktype==ID_KE) {
1213                         G.v2d->cur.xmin= (float)-0.1;
1214                         G.v2d->cur.xmax= EFRA;
1215                         G.v2d->cur.ymin= (float)-0.1;
1216                         G.v2d->cur.ymax= (float)+2.1;
1217                 }
1218
1219         }
1220 }
1221
1222
1223 void test_editipo()
1224 {
1225         Ipo *ipo;
1226         ID *from;
1227         
1228         if(G.sipo->editipo==0){
1229                 make_editipo();
1230         }
1231         else {
1232                 ipo= get_ipo_to_edit(&from);
1233
1234                 if(G.sipo->ipo != ipo || G.sipo->from!=from)
1235                         make_editipo();
1236                 
1237         }
1238
1239         if (G.sipo->pin)
1240                 return;
1241
1242
1243         if(G.sipo->ipo)
1244                 G.sipo->ipo->cur = G.v2d->cur;
1245
1246 }
1247
1248 /* ****************************************** */
1249
1250 int totipo_edit, totipo_sel, totipo_vis, totipo_vert, totipo_vertsel, totipo_key, totipo_keysel;
1251
1252 void get_status_editipo()
1253 {
1254         EditIpo *ei;
1255         IpoKey *ik;
1256         BezTriple *bezt;
1257         int a, b;
1258         
1259         totipo_vis= 0;
1260         totipo_sel= 0;
1261         totipo_edit= 0;
1262         totipo_vert= 0;
1263         totipo_vertsel= 0;
1264         totipo_key= 0;
1265         totipo_keysel= 0;
1266         
1267         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1268         
1269         ei= G.sipo->editipo;
1270         if(ei==0) return;
1271         for(a=0; a<G.sipo->totipo; a++) {
1272                 if( ei->flag & IPO_VISIBLE ) {
1273                         totipo_vis++;
1274                         if(ei->flag & IPO_SELECT) totipo_sel++;
1275                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
1276                                 
1277                                 /* if showkey: do count the vertices (for grab) */
1278                                 if(G.sipo->showkey==0) totipo_edit++;
1279                                 
1280                                 if(ei->icu) {
1281                                         if(ei->icu->bezt) {
1282                                                 bezt= ei->icu->bezt;
1283                                                 b= ei->icu->totvert;
1284                                                 while(b--) {
1285                                                         if(ei->icu->ipo==IPO_BEZ) {
1286                                                                 if(bezt->f1 & 1) totipo_vertsel++;
1287                                                                 if(bezt->f3 & 1) totipo_vertsel++;
1288                                                                 totipo_vert+= 2;
1289                                                         }
1290                                                         if(bezt->f2 & 1) totipo_vertsel++;
1291                                                         
1292                                                         totipo_vert++;
1293                                                         bezt++;
1294                                                 }
1295                                         }
1296                                 }
1297                         }
1298                 }
1299                 ei++;
1300         }
1301         
1302         if(G.sipo->showkey) {
1303                 ik= G.sipo->ipokey.first;
1304                 while(ik) {
1305                         totipo_key++;
1306                         if(ik->flag & 1) totipo_keysel++;
1307                         ik= ik->next;
1308                 }
1309         }
1310 }
1311
1312
1313
1314 void update_editipo_flags()
1315 {
1316         EditIpo *ei;
1317         IpoKey *ik;
1318         short flag;/*unsigned int flag;*/
1319         int a;
1320         
1321         ei= G.sipo->editipo;
1322         if(ei) {
1323                 for(a=0; a<G.sipo->totipo; a++, ei++) {
1324                         ei->flag &= ~IPO_VISIBLE;
1325                         flag= (1<<IPO_IS_SELECTED);
1326                         if( ei->flag & flag ) ei->flag |= IPO_VISIBLE;
1327                         
1328                         if(ei->icu) ei->icu->flag= ei->flag;
1329                         
1330                 }
1331         }
1332         if(G.sipo->showkey) {
1333                 ik= G.sipo->ipokey.first;
1334                 while(ik) {
1335                         for(a=0; a<G.sipo->totipo; a++) {
1336                                 if(ik->data[a]) {
1337                                         if(ik->flag & 1) {
1338                                                 ik->data[a]->f1 |= 1;
1339                                                 ik->data[a]->f2 |= 1;
1340                                                 ik->data[a]->f3 |= 1;
1341                                         }
1342                                         else {
1343                                                 ik->data[a]->f1 &= ~1;
1344                                                 ik->data[a]->f2 &= ~1;
1345                                                 ik->data[a]->f3 &= ~1;
1346                                         }
1347                                 }
1348                         }
1349                         ik= ik->next;
1350                 }
1351         }
1352 }
1353
1354 void set_editflag_editipo()
1355 {
1356         EditIpo *ei;
1357         int a; /*  , tot= 0, ok= 0; */
1358         
1359         /* after showkey immediately go to editing of selected points */
1360         if(G.sipo->showkey) {
1361                 G.sipo->showkey= 0;
1362                 if(G.sipo->ipo) G.sipo->ipo->showkey= 0;
1363                 ei= G.sipo->editipo;
1364                 for(a=0; a<G.sipo->totipo; a++, ei++) ei->flag |= IPO_SELECT;
1365                 scrarea_queue_headredraw(curarea);
1366                 allqueue(REDRAWVIEW3D, 0);
1367         }
1368         
1369         get_status_editipo();
1370         
1371         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1372         
1373         ei= G.sipo->editipo;
1374         for(a=0; a<G.sipo->totipo; a++, ei++) {         
1375                 if(ei->icu) {
1376                         if(ei->flag & IPO_VISIBLE) {
1377                                 
1378                                 if(totipo_edit==0 && (ei->flag & IPO_SELECT)) {
1379                                         ei->flag |= IPO_EDIT;
1380                                         ei->icu->flag= ei->flag;
1381                                 }
1382                                 else if(totipo_edit && (ei->flag & IPO_EDIT)) {
1383                                         ei->flag -= IPO_EDIT;
1384                                         ei->icu->flag= ei->flag;
1385                                 }
1386                                 else if(totipo_vis==1) {
1387                                         if(ei->flag & IPO_EDIT) ei->flag -= IPO_EDIT;
1388                                         else ei->flag |= IPO_EDIT;
1389                                         ei->icu->flag= ei->flag;
1390                                 }
1391                         }
1392                 }
1393         }
1394         scrarea_queue_headredraw(curarea);
1395         scrarea_queue_winredraw(curarea);
1396 }
1397
1398 void ipo_toggle_showkey(void) {
1399         if(G.sipo->showkey) {
1400                 G.sipo->showkey= 0;
1401                 swap_selectall_editipo();       /* sel all */
1402         }
1403         else G.sipo->showkey= 1;
1404         free_ipokey(&G.sipo->ipokey);
1405         if(G.sipo->ipo) G.sipo->ipo->showkey= G.sipo->showkey;
1406
1407         BIF_undo_push("Toggle show key Ipo");
1408 }
1409
1410 void swap_selectall_editipo()
1411 {
1412         Object *ob;
1413         EditIpo *ei;
1414         IpoKey *ik;
1415         BezTriple *bezt;
1416         int a, b; /*  , sel=0; */
1417         
1418         
1419         deselectall_key();
1420
1421         get_status_editipo();
1422
1423         if(G.sipo->showkey) {
1424                 ik= G.sipo->ipokey.first;
1425                 while(ik) {
1426                         if(totipo_vertsel) ik->flag &= ~1;
1427                         else ik->flag |= 1;
1428                         ik= ik->next;
1429                 }
1430                 update_editipo_flags();
1431
1432                 if(G.sipo->showkey && G.sipo->blocktype==ID_OB ) {
1433                         ob= OBACT;
1434                         if(ob && (ob->ipoflag & OB_DRAWKEY)) draw_object_ext(BASACT);
1435                 }
1436         }
1437         else if(totipo_edit==0) {
1438                 ei= G.sipo->editipo;
1439                 if (ei){
1440                         for(a=0; a<G.sipo->totipo; a++) {
1441                                 if( ei->flag & IPO_VISIBLE ) {
1442                                         if(totipo_sel) ei->flag &= ~IPO_SELECT;
1443                                         else ei->flag |= IPO_SELECT;
1444                                 }
1445                                 ei++;
1446                         }
1447                         update_editipo_flags();
1448                 }
1449         }
1450         else {
1451                 ei= G.sipo->editipo;
1452                 for(a=0; a<G.sipo->totipo; a++) {
1453                         if ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu ) {
1454                                 bezt= ei->icu->bezt;
1455                                 if(bezt) {
1456                                         b= ei->icu->totvert;
1457                                         while(b--) {
1458                                                 if(totipo_vertsel) {
1459                                                         bezt->f1= bezt->f2= bezt->f3= 0;
1460                                                 }
1461                                                 else {
1462                                                         bezt->f1= bezt->f2= bezt->f3= 1;
1463                                                 }
1464                                                 bezt++;
1465                                         }
1466                                 }
1467                         }
1468                         ei++;
1469                 }
1470                 
1471         }
1472         
1473         BIF_undo_push("Swap select all Ipo");
1474         scrarea_queue_winredraw(curarea);
1475         
1476 }
1477
1478 void swap_visible_editipo()
1479 {
1480         EditIpo *ei;
1481         Object *ob;
1482         int a; /*  , sel=0; */
1483         
1484         get_status_editipo();
1485         
1486         
1487         ei= G.sipo->editipo;
1488         for(a=0; a<G.sipo->totipo; a++) {
1489                 if(totipo_vis==0) {
1490                         if(ei->icu) {
1491                                 ei->flag |= IPO_VISIBLE;
1492                                 ei->flag |= (1<<IPO_IS_SELECTED);
1493                         }
1494                 }
1495                 else ei->flag &= ~IPO_VISIBLE;
1496                 ei++;
1497         }
1498         
1499         update_editipo_flags();
1500         
1501         if(G.sipo->showkey) {
1502                 
1503                 make_ipokey();
1504                 
1505                 ob= OBACT;
1506                 if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
1507         }
1508
1509         scrarea_queue_winredraw(curarea);
1510         BIF_undo_push("Swap Visible Ipo");      
1511 }
1512
1513 void deselectall_editipo()
1514 {
1515         EditIpo *ei;
1516         IpoKey *ik;
1517         BezTriple *bezt;
1518         int a, b; /*  , sel=0; */
1519         
1520         deselectall_key();
1521
1522         get_status_editipo();
1523         
1524         if(G.sipo->showkey) {
1525                 ik= G.sipo->ipokey.first;
1526                 while(ik) {
1527                         ik->flag &= ~1;
1528                         ik= ik->next;
1529                 }
1530                 update_editipo_flags();
1531
1532         }
1533         else if(totipo_edit==0) {
1534                 
1535                 ei= G.sipo->editipo;
1536                 for(a=0; a<G.sipo->totipo; a++) {
1537                         if( ei->flag & IPO_VISIBLE ) {
1538                                 ei->flag &= ~IPO_SELECT;
1539                         }
1540                         ei++;
1541                 }
1542                 update_editipo_flags();
1543         }
1544         else {
1545                 ei= G.sipo->editipo;
1546                 for(a=0; a<G.sipo->totipo; a++) {
1547                         if ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu ) {
1548                                 if(ei->icu->bezt) {
1549                                         bezt= ei->icu->bezt;
1550                                         b= ei->icu->totvert;
1551                                         while(b--) {
1552                                                 bezt->f1= bezt->f2= bezt->f3= 0;
1553                                                 bezt++;
1554                                         }
1555                                 }
1556                         }
1557                         ei++;
1558                 }
1559         }
1560         
1561         BIF_undo_push("(De)select all Ipo");
1562         scrarea_queue_winredraw(curarea);
1563 }
1564
1565 short findnearest_ipovert(IpoCurve **icu, BezTriple **bezt)
1566 {
1567         /* selected verts get a disadvantage */
1568         /* in icu and (bezt or bp) the nearest is written */
1569         /* return 0 1 2: handlepunt */
1570         EditIpo *ei;
1571         BezTriple *bezt1;
1572         int dist= 100, temp, a, b;
1573         short mval[2], hpoint=0;
1574
1575         *icu= 0;
1576         *bezt= 0;
1577
1578         getmouseco_areawin(mval);
1579
1580         ei= G.sipo->editipo;
1581         for(a=0; a<G.sipo->totipo; a++, ei++) {
1582                 if ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu) {
1583                         
1584                         if(ei->icu->bezt) {
1585                                 bezt1= ei->icu->bezt;
1586                                 b= ei->icu->totvert;
1587                                 while(b--) {
1588
1589                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[0], bezt1->s[0]);
1590                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[1], bezt1->s[1]);
1591                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[2], bezt1->s[2]);
1592                                                                                 
1593                                         if(ei->disptype==IPO_DISPBITS) {
1594                                                 temp= abs(mval[0]- bezt1->s[1][0]);
1595                                         }
1596                                         else temp= abs(mval[0]- bezt1->s[1][0])+ abs(mval[1]- bezt1->s[1][1]);
1597
1598                                         if( bezt1->f2 & 1) temp+=5;
1599                                         if(temp<dist) { 
1600                                                 hpoint= 1; 
1601                                                 *bezt= bezt1; 
1602                                                 dist= temp; 
1603                                                 *icu= ei->icu; 
1604                                         }
1605                                         
1606                                         if(ei->disptype!=IPO_DISPBITS && ei->icu->ipo==IPO_BEZ) {
1607                                                 /* middle points get an advantage */
1608                                                 temp= -3+abs(mval[0]- bezt1->s[0][0])+ abs(mval[1]- bezt1->s[0][1]);
1609                                                 if( bezt1->f1 & 1) temp+=5;
1610                                                 if(temp<dist) { 
1611                                                         hpoint= 0; 
1612                                                         *bezt= bezt1; 
1613                                                         dist= temp; 
1614                                                         *icu= ei->icu; 
1615                                                 }
1616                 
1617                                                 temp= abs(mval[0]- bezt1->s[2][0])+ abs(mval[1]- bezt1->s[2][1]);
1618                                                 if( bezt1->f3 & 1) temp+=5;
1619                                                 if(temp<dist) { 
1620                                                         hpoint= 2; 
1621                                                         *bezt=bezt1; 
1622                                                         dist= temp; 
1623                                                         *icu= ei->icu; 
1624                                                 }
1625                                         }
1626                                         bezt1++;
1627                                 }
1628                         }
1629                 }
1630         }
1631
1632         return hpoint;
1633 }
1634
1635
1636 void move_to_frame()
1637 {
1638         EditIpo *ei;
1639         BezTriple *bezt;
1640         ID *id;
1641         float cfra;
1642         int a, b;
1643         
1644         if(G.sipo->editipo==0) return;
1645
1646         ei= G.sipo->editipo;
1647
1648         for(a=0; a<G.sipo->totipo; a++, ei++) {
1649                 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
1650                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
1651                         
1652                                 if(ei->icu->bezt) {
1653                                         
1654                                         b= ei->icu->totvert;
1655                                         bezt= ei->icu->bezt;
1656                                         while(b--) {
1657                                                 if(BEZSELECTED(bezt)) {
1658                                                 
1659                                                         cfra=  bezt->vec[1][0]/G.scene->r.framelen;
1660
1661                                                         id= G.sipo->from;
1662                                                         if(id && GS(id->name)==ID_OB ) {
1663                                                                 Object *ob= (Object *)id;
1664                                                                 if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
1665                                                                         cfra+= ob->sf/G.scene->r.framelen;
1666                                                                 }
1667                                                         }
1668                                                         CFRA= (short)floor(cfra+0.5);
1669                                                 
1670                                                         if(CFRA < 1) CFRA= 1;
1671                                                         update_for_newframe();
1672                                                         
1673                                                         break;
1674                                                 }
1675                                                 bezt++;
1676                                         }
1677                                 }
1678                         }
1679                 }
1680         }
1681         BIF_undo_push("Set frame to selected Ipo vertex");
1682 }
1683
1684 /* *********************************** */
1685
1686 void do_ipowin_buts(short event)
1687 {
1688         EditIpo *ei = 0;
1689         int a;
1690         if((G.qual & LR_SHIFTKEY)==0) {
1691                 if(event>G.sipo->totipo) return;
1692                 ei = G.sipo->editipo;
1693                 for(a=0; a<G.sipo->totipo; a++) {
1694                         if(a==event) ei->flag |= (1<<IPO_IS_SELECTED);
1695                         else ei->flag &= ~(1<<IPO_IS_SELECTED);
1696                         ei++;
1697                 }
1698         }
1699         scrarea_queue_winredraw(curarea);
1700         
1701         update_editipo_flags();
1702
1703         if(G.sipo->showkey) {
1704                 make_ipokey();
1705                 if(G.sipo->blocktype==ID_OB) allqueue(REDRAWVIEW3D, 0);
1706         }
1707
1708 }
1709
1710 void do_ipo_selectbuttons()
1711 {
1712         EditIpo *ei, *ei1;
1713         int a, nr;
1714         short mval[2];
1715         
1716         if(G.sipo->showkey) return;
1717         
1718         /* do not allow editipo here: convert editipos to selected */
1719         get_status_editipo();
1720         if(totipo_edit) {
1721                 set_editflag_editipo();
1722         }
1723         
1724         /* which */
1725         getmouseco_areawin(mval);
1726
1727         nr= -(mval[1]-curarea->winy+30-G.sipo->butofs-IPOBUTY)/IPOBUTY;
1728         if(nr>=0 && nr<G.sipo->totipo) {
1729                 ei= G.sipo->editipo;
1730                 ei+= nr;
1731                 
1732                 if(ei->icu) {
1733                         if((ei->flag & IPO_VISIBLE)==0) {
1734                                 ei->flag |= IPO_VISIBLE;
1735                                 ei->flag |= (1<<IPO_IS_SELECTED);
1736                         }
1737         
1738                         if((G.qual & LR_SHIFTKEY)==0) {
1739                                 ei1= G.sipo->editipo;
1740                                 for(a=0; a<G.sipo->totipo; a++) {
1741                                         ei1->flag &= ~IPO_SELECT;
1742                                         ei1++;
1743                                 }
1744                         }
1745
1746                         if(ei->flag & IPO_SELECT) {
1747                                 ei->flag &= ~IPO_SELECT;
1748                         }
1749                         else {
1750                                 ei->flag |= IPO_SELECT;
1751                         }
1752                         
1753                         update_editipo_flags();
1754                         scrarea_queue_winredraw(curarea);
1755                 }
1756         }
1757         BIF_undo_push("Select Ipo curve");
1758 }
1759
1760 /* ******************************************* */
1761
1762 EditIpo *get_editipo()
1763 {
1764         EditIpo *ei;
1765         int a; /*  , sel=0; */
1766         
1767         get_status_editipo();
1768         
1769         if(totipo_edit>1) {
1770                 return 0;
1771         }
1772         if(G.sipo->editipo==0) return 0;
1773         
1774         ei= G.sipo->editipo;
1775         for(a=0; a<G.sipo->totipo; a++) {
1776                 if(ei->flag & IPO_VISIBLE) {
1777                         if( ei->flag & IPO_EDIT ) return ei;
1778                         else if(totipo_vis==1) return ei;
1779                         
1780                         if(ei->flag & IPO_SELECT) {
1781                                 if(totipo_sel==1) return ei;
1782                         }
1783                 }
1784                 ei++;
1785         }
1786         return 0;
1787 }
1788
1789
1790 Ipo *get_ipo(ID *from, short type, int make)
1791 {
1792         Object *ob;
1793         Material *ma;
1794         Tex *tex;
1795         Curve *cu;
1796         Sequence *seq;
1797         Key *key;
1798         World *wo;
1799         Lamp *la;
1800         Camera *ca;
1801         Ipo *ipo= 0;
1802         bAction *act;
1803
1804         if( type==ID_OB) {
1805                 ob= (Object *)from;
1806                 if(ob->id.lib) return 0;
1807                 
1808                 ipo= ob->ipo;
1809                 if(make && ipo==0) ipo= ob->ipo= add_ipo("ObIpo", ID_OB);       
1810         }
1811         else if( type==IPO_CO){
1812                 ob= (Object *)from;
1813                 if(ob->id.lib) return 0;
1814
1815                 if (ob->activecon){
1816                         ipo= ob->activecon->ipo;
1817                         if(make && ipo==0) ipo= ob->activecon->ipo= add_ipo("CoIpo", IPO_CO);   
1818                 }
1819         }
1820         else if( type==ID_AC) {
1821                 act= (bAction *)from;
1822                 if (!act->achan) return 0;
1823                 if (act->id.lib) return 0;
1824                 ipo= act->achan->ipo;
1825
1826                 /* This should never happen */
1827                 if(make && ipo==0) ipo= act->achan->ipo= add_ipo("AcIpo", ID_AC);
1828         }
1829         else if( type==ID_MA) {
1830                 ma= (Material *)from;
1831                 if(ma->id.lib) return 0;
1832                 ipo= ma->ipo;
1833                 
1834                 if(make && ipo==0) ipo= ma->ipo= add_ipo("MatIpo", ID_MA);
1835         }
1836         else if( type==ID_TE) {
1837                 tex= (Tex *)from;
1838                 if(tex->id.lib) return 0;
1839                 ipo= tex->ipo;
1840                 
1841                 if(make && ipo==0) ipo= tex->ipo= add_ipo("TexIpo", ID_TE);
1842         }
1843         else if( type==ID_SEQ) {
1844                 seq= (Sequence *)from;
1845
1846                 if((seq->type & SEQ_EFFECT)||(seq->type == SEQ_SOUND)) {
1847                         ipo= seq->ipo;
1848                         if(make && ipo==0) ipo= seq->ipo= add_ipo("SeqIpo", ID_SEQ);
1849                 }
1850                 else return 0;
1851         }               
1852         else if( type==ID_CU) {
1853                 cu= (Curve *)from;
1854                 if(cu->id.lib) return 0;
1855                 ipo= cu->ipo;
1856                 
1857                 if(make && ipo==0) ipo= cu->ipo= add_ipo("CuIpo", ID_CU);
1858         }
1859         else if( type==ID_KE) {
1860                 key= (Key *)from;
1861                 if(key->id.lib) return 0;
1862                 ipo= key->ipo;
1863                 
1864                 if(make && ipo==0) ipo= key->ipo= add_ipo("KeyIpo", ID_KE);
1865         }
1866         else if( type==ID_WO) {
1867                 wo= (World *)from;
1868                 if(wo->id.lib) return 0;
1869                 ipo= wo->ipo;
1870                 
1871                 if(make && ipo==0) ipo= wo->ipo= add_ipo("WoIpo", ID_WO);
1872         }
1873         else if( type==ID_LA) {
1874                 la= (Lamp *)from;
1875                 if(la->id.lib) return 0;
1876                 ipo= la->ipo;
1877                 
1878                 if(make && ipo==0) ipo= la->ipo= add_ipo("LaIpo", ID_LA);
1879         }
1880         else if( type==ID_CA) {
1881                 ca= (Camera *)from;
1882                 if(ca->id.lib) return 0;
1883                 ipo= ca->ipo;
1884                 
1885                 if(make && ipo==0) ipo= ca->ipo= add_ipo("CaIpo", ID_CA);
1886         }
1887         else if( type==ID_SO) {
1888                 bSound *snd= (bSound *)from;
1889                 if(snd->id.lib) return 0;
1890                 ipo= snd->ipo;
1891                 
1892                 if(make && ipo==0) ipo= snd->ipo= add_ipo("SndIpo", ID_SO);
1893         }
1894         else return 0;
1895         
1896         return ipo;     
1897 }
1898
1899
1900 // this function should not have the G.sipo in it...
1901
1902 IpoCurve *get_ipocurve(ID *from, short type, int adrcode, Ipo *useipo)
1903 {
1904         Ipo *ipo= 0;
1905         IpoCurve *icu=0;
1906         
1907         /* return 0 if lib */
1908         /* also test if ipo and ipocurve exist */
1909
1910         if (useipo==NULL) {
1911
1912                 if (G.sipo==NULL || G.sipo->pin==0){
1913                         ipo= get_ipo(from, type, 1);    /* 1= make */
1914                 }
1915                 else
1916                         ipo = G.sipo->ipo;
1917
1918                 
1919                 if(G.sipo) {
1920                         if (G.sipo->pin==0) G.sipo->ipo= ipo;
1921                 }
1922         }
1923         else
1924                 ipo= useipo;
1925
1926                 
1927         if(ipo && ipo->id.lib==0) {
1928         
1929                 icu= ipo->curve.first;
1930                 while(icu) {
1931                         if(icu->adrcode==adrcode) break;
1932                         icu= icu->next;
1933                 }
1934                 if(icu==0) {
1935                         icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
1936                         
1937                         icu->flag |= IPO_VISIBLE;
1938
1939                         if (!useipo && G.sipo && G.sipo->pin)
1940                                 icu->blocktype = G.sipo->blocktype;
1941                         else
1942                                 icu->blocktype= type;
1943                         icu->adrcode= adrcode;
1944                         
1945                         set_icu_vars(icu);
1946                         
1947                         BLI_addtail( &(ipo->curve), icu);
1948                 }
1949         }
1950         return icu;
1951 }
1952
1953 void insert_vert_ipo(IpoCurve *icu, float x, float y)
1954 {
1955         BezTriple *bezt, beztr, *newbezt;
1956         int a = 0, h1, h2;
1957         
1958         memset(&beztr, 0, sizeof(BezTriple));
1959         beztr.vec[0][0]= x; // set all three points, for nicer start position
1960         beztr.vec[0][1]= y;
1961         beztr.vec[1][0]= x;
1962         beztr.vec[1][1]= y;
1963         beztr.vec[2][0]= x;
1964         beztr.vec[2][1]= y;
1965         beztr.hide= IPO_BEZ;
1966         beztr.f1= beztr.f2= beztr.f3= SELECT;
1967         beztr.h1= beztr.h2= HD_AUTO;
1968                 
1969         bezt= icu->bezt;
1970                 
1971         if(bezt==0) {
1972                 icu->bezt= MEM_callocN( sizeof(BezTriple), "beztriple");
1973                 *(icu->bezt)= beztr;
1974                 icu->totvert= 1;
1975         }
1976         else {
1977                 /* all vertices deselect */
1978                 for(a=0; a<icu->totvert; a++, bezt++) {
1979                         bezt->f1= bezt->f2= bezt->f3= 0;
1980                 }
1981         
1982                 bezt= icu->bezt;
1983                 for(a=0; a<=icu->totvert; a++, bezt++) {
1984                         
1985                         /* no double points */
1986                         if(a<icu->totvert && (bezt->vec[1][0]>x-IPOTHRESH && bezt->vec[1][0]<x+IPOTHRESH)) {
1987                                 *(bezt)= beztr;
1988                                 break;
1989                         }
1990                         if(a==icu->totvert || bezt->vec[1][0] > x) {
1991                                 newbezt= MEM_callocN( (icu->totvert+1)*sizeof(BezTriple), "beztriple");
1992                                 
1993                                 if(a>0) memcpy(newbezt, icu->bezt, a*sizeof(BezTriple));
1994                                 
1995                                 bezt= newbezt+a;
1996                                 *(bezt)= beztr;
1997                                 
1998                                 if(a<icu->totvert) memcpy(newbezt+a+1, icu->bezt+a, (icu->totvert-a)*sizeof(BezTriple));
1999                                 
2000                                 MEM_freeN(icu->bezt);
2001                                 icu->bezt= newbezt;
2002                                 
2003                                 icu->totvert++;
2004                                 break;
2005                         }
2006                 }
2007         }
2008         
2009         
2010         calchandles_ipocurve(icu);
2011         
2012         /* set handletype */
2013         if(icu->totvert>2) {
2014                 h1= h2= HD_AUTO;
2015                 if(a>0) h1= (bezt-1)->h2;
2016                 if(a<icu->totvert-1) h2= (bezt+1)->h1;
2017                 bezt->h1= h1;
2018                 bezt->h2= h2;
2019
2020                 calchandles_ipocurve(icu);
2021         }
2022 }
2023
2024 void add_vert_ipo()
2025 {
2026         EditIpo *ei;
2027         float x, y;
2028         int val;
2029         short mval[2];
2030
2031         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
2032         if(G.sipo->showkey) {
2033                 G.sipo->showkey= 0;
2034                 free_ipokey(&G.sipo->ipokey);
2035         }
2036         
2037         getmouseco_areawin(mval);
2038         
2039         if(mval[0]>G.v2d->mask.xmax) return;
2040         
2041         ei= get_editipo();
2042         if(ei==0) {
2043                 error("Too many EditIpos");
2044                 return;
2045         }
2046         
2047         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
2048         
2049         if(ei->icu==0) {
2050                 if(G.sipo->from)
2051                         ei->icu= get_ipocurve(G.sipo->from, G.sipo->blocktype, ei->adrcode, 0);
2052         }
2053         if(ei->icu==0) return;
2054
2055         if(ei->disptype==IPO_DISPBITS) {
2056                 ei->icu->vartype= IPO_BITS;
2057                 val= (int)floor(y-0.5);
2058                 if(val<0) val= 0;
2059                 y= (float)(1 << val);
2060         }
2061         
2062         insert_vert_ipo(ei->icu, x, y);
2063
2064         /* to be sure: if icu was 0, or only 1 curve visible */
2065         ei->flag |= IPO_SELECT;
2066         ei->icu->flag= ei->flag;
2067         
2068         editipo_changed(G.sipo, 1);
2069         BIF_undo_push("Add Ipo vertex");
2070 }
2071
2072 void add_duplicate_editipo()
2073 {
2074         Object *ob;
2075         EditIpo *ei;
2076         IpoCurve *icu;
2077         BezTriple *bezt, *beztn, *newb;
2078         int tot, a, b;
2079         
2080         get_status_editipo();
2081         if(totipo_vertsel==0) return;
2082         
2083         ei= G.sipo->editipo;
2084         for(a=0; a<G.sipo->totipo; a++, ei++) {
2085                 if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) {
2086                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2087                                 icu= ei->icu;
2088                                 
2089                                 /* how many points */
2090                                 tot= 0;
2091                                 b= icu->totvert;
2092                                 bezt= icu->bezt;
2093                                 while(b--) {
2094                                         if(bezt->f2 & 1) tot++;
2095                                         bezt++;
2096                                 }
2097                                 
2098                                 if(tot) {
2099                                         icu->totvert+= tot;
2100                                         newb= beztn= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2101                                         bezt= icu->bezt;
2102                                         b= icu->totvert-tot;
2103                                         while(b--) {
2104                                                 *beztn= *bezt;
2105                                                 if(bezt->f2 & 1) {
2106                                                         beztn->f1= beztn->f2= beztn->f3= 0;
2107                                                         beztn++;
2108                                                         *beztn= *bezt;
2109                                                 }
2110                                                 beztn++;
2111                                                 bezt++;
2112                                         }
2113                                         MEM_freeN(icu->bezt);
2114                                         icu->bezt= newb;
2115                                         
2116                                         calchandles_ipocurve(icu);
2117                                 }
2118                         }
2119                 }
2120         }
2121         
2122         if(G.sipo->showkey) {
2123                 make_ipokey();
2124                 if(G.sipo->blocktype==ID_OB) {
2125                         ob= OBACT;
2126                         if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
2127                 }
2128         }
2129         BIF_undo_push("Duplicate Ipo");
2130         transform_ipo('g');
2131 }
2132
2133 void remove_doubles_ipo()
2134 {
2135         EditIpo *ei;
2136         IpoKey *ik, *ikn;
2137         BezTriple *bezt, *newb, *new1;
2138         float val;
2139         int mode, a, b;
2140         
2141         ei= G.sipo->editipo;
2142         for(a=0; a<G.sipo->totipo; a++, ei++) {
2143                 if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) {
2144                         
2145                         /* OR the curve is selected OR in editmode OR in keymode */
2146                         mode= 0;
2147                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) mode= 1;
2148                         else if(ei->flag & IPO_SELECT) mode= 2;
2149                         
2150                         if(mode) {
2151                                 bezt= ei->icu->bezt;
2152                                 newb= new1= MEM_mallocN(ei->icu->totvert*sizeof(BezTriple), "newbezt");
2153                                 *newb= *bezt;
2154                                 b= ei->icu->totvert-1;
2155                                 bezt++;
2156                                 while(b--) {
2157                                         
2158                                         /* can we remove? */
2159                                         if(mode==2 || (bezt->f2 & 1)) {
2160                                         
2161                                                 /* are the points different? */
2162                                                 if( fabs( bezt->vec[1][0]-newb->vec[1][0] ) > 0.9 ) {
2163                                                         newb++;
2164                                                         *newb= *bezt;
2165                                                 }
2166                                                 else {
2167                                                         /* median */
2168                                                         VecMidf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2169                                                         VecMidf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2170                                                         VecMidf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2171                                                         
2172                                                         newb->h1= newb->h2= HD_FREE;
2173                                                         
2174                                                         ei->icu->totvert--;
2175                                                 }
2176                                                 
2177                                         }
2178                                         else {
2179                                                 newb++;
2180                                                 *newb= *bezt;
2181                                         }
2182                                         bezt++;
2183                                 }
2184                                 
2185                                 MEM_freeN(ei->icu->bezt);
2186                                 ei->icu->bezt= new1;
2187                                 
2188                                 calchandles_ipocurve(ei->icu);                          
2189                         }
2190                 }
2191         }
2192         
2193         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2194
2195         /* remove double keys */
2196         if(G.sipo->showkey) {
2197                 ik= G.sipo->ipokey.first;
2198                 ikn= ik->next;
2199                 
2200                 while(ik && ikn) {
2201                         if( (ik->flag & 1) && (ikn->flag & 1) ) {
2202                                 if( fabs(ik->val-ikn->val) < 0.9 ) {
2203                                         val= (float)((ik->val + ikn->val)/2.0);
2204                                         
2205                                         for(a=0; a<G.sipo->totipo; a++) {
2206                                                 if(ik->data[a]) ik->data[a]->vec[1][0]= val;
2207                                                 if(ikn->data[a]) ikn->data[a]->vec[1][0]= val;                                          
2208                                         }
2209                                 }
2210                         }
2211                         ik= ikn;
2212                         ikn= ikn->next;
2213
2214                 }
2215                 
2216                 editipo_changed(G.sipo, 1);     /* makes ipokeys agian! */
2217
2218         }
2219         deselectall_editipo();
2220 }
2221
2222 void join_ipo_menu(void)
2223 {
2224         int mode = 0;
2225         mode= pupmenu("Join %t|All Selected %x1|Selected Doubles %x2");
2226         
2227         if (mode == -1) return;
2228         
2229         join_ipo(mode);
2230 }
2231
2232 void join_ipo(int mode)
2233 {
2234         EditIpo *ei;
2235         IpoKey *ik;
2236         IpoCurve *icu;
2237         BezTriple *bezt, *beztn, *newb;
2238         float val;
2239         int tot, a, b;
2240         
2241         get_status_editipo();
2242         
2243         /* Mode events:
2244          * All Selected: 1
2245          * Selected Doubles: 2
2246          */
2247         
2248         if( mode==2 ) {
2249                 remove_doubles_ipo();
2250                 return;
2251         }
2252         
2253         /* first: multiple selected verts in 1 curve */
2254         ei= G.sipo->editipo;
2255         for(a=0; a<G.sipo->totipo; a++, ei++) {
2256                 if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) {
2257                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2258                                 icu= ei->icu;
2259                                 
2260                                 /* how many points */
2261                                 tot= 0;
2262                                 b= icu->totvert;
2263                                 bezt= icu->bezt;
2264                                 while(b--) {
2265                                         if(bezt->f2 & 1) tot++;
2266                                         bezt++;
2267                                 }
2268                                 
2269                                 if(tot>1) {
2270                                         tot--;
2271                                         icu->totvert-= tot;
2272                                         
2273                                         newb= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2274                                         /* the first point is the new one */
2275                                         beztn= newb+1;
2276                                         tot= 0;
2277                                         
2278                                         bezt= icu->bezt;
2279                                         b= icu->totvert+tot+1;
2280                                         while(b--) {
2281                                                 
2282                                                 if(bezt->f2 & 1) {
2283                                                         if(tot==0) *newb= *bezt;
2284                                                         else {
2285                                                                 VecAddf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2286                                                                 VecAddf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2287                                                                 VecAddf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2288                                                         }
2289                                                         tot++;
2290                                                 }
2291                                                 else {
2292                                                         *beztn= *bezt;
2293                                                         beztn++;
2294                                                 }
2295                                                 bezt++;
2296                                         }
2297                                         
2298                                         VecMulf(newb->vec[0], (float)(1.0/((float)tot)));
2299                                         VecMulf(newb->vec[1], (float)(1.0/((float)tot)));
2300                                         VecMulf(newb->vec[2], (float)(1.0/((float)tot)));
2301                                         
2302                                         MEM_freeN(icu->bezt);
2303                                         icu->bezt= newb;
2304                                         
2305                                         sort_time_ipocurve(icu);
2306                                         calchandles_ipocurve(icu);
2307                                 }
2308                         }
2309                 }
2310         }
2311         
2312         /* next: in keymode: join multiple selected keys */
2313         
2314         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2315         
2316         if(G.sipo->showkey) {
2317                 ik= G.sipo->ipokey.first;
2318                 val= 0.0;
2319                 tot= 0;
2320                 while(ik) {
2321                         if(ik->flag & 1) {
2322                                 for(a=0; a<G.sipo->totipo; a++) {
2323                                         if(ik->data[a]) {
2324                                                 val+= ik->data[a]->vec[1][0];
2325                                                 break;
2326                                         }
2327                                 }
2328                                 tot++;
2329                         }
2330                         ik= ik->next;
2331                 }
2332                 if(tot>1) {
2333                         val/= (float)tot;
2334                         
2335                         ik= G.sipo->ipokey.first;
2336                         while(ik) {
2337                                 if(ik->flag & 1) {
2338                                         for(a=0; a<G.sipo->totipo; a++) {
2339                                                 if(ik->data[a]) {
2340                                                         ik->data[a]->vec[1][0]= val;
2341                                                 }
2342                                         }
2343                                 }
2344                                 ik= ik->next;
2345                         }
2346                         editipo_changed(G.sipo, 0);
2347                 }
2348         }
2349         deselectall_editipo();
2350         BIF_undo_push("Join Ipo");
2351 }
2352
2353 void ipo_snap_menu(void)
2354 {
2355         short event;
2356         
2357         event= pupmenu("Snap %t|Horizontal %x1|To Next %x2|To Frame %x3|To Current Frame%x4");
2358         if(event < 1) return;
2359
2360         ipo_snap(event);
2361 }
2362
2363 void ipo_snap(short event)
2364 {
2365         EditIpo *ei;
2366         BezTriple *bezt;
2367         float dx = 0.0;
2368         int a, b;
2369         short ok, ok2;
2370         
2371         /* events:
2372          * Horizontal : 1
2373          * To Next: 2
2374          * To Frame: 3
2375          * To Current Frame: 4
2376          */
2377          
2378         get_status_editipo();
2379
2380         ei= G.sipo->editipo;
2381         for(b=0; b<G.sipo->totipo; b++, ei++) {
2382                 if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) {
2383                 
2384                         ok2= 0;
2385                         if(G.sipo->showkey) ok2= 1;
2386                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok2= 2;
2387                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok2= 3;
2388                         
2389                         if(ok2) {
2390                                 bezt= ei->icu->bezt;
2391                                 a= ei->icu->totvert;
2392                                 while(a--) {
2393                                         ok= 0;
2394                                         if(totipo_vert) {
2395                                                  if(bezt->f2 & 1) ok= 1;
2396                                         }
2397                                         else ok= 1;
2398                                         
2399                                         if(ok) {
2400                                                 if(event==1) {
2401                                                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
2402                                                         if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2403                                                         if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2404                                                 }
2405                                                 else if(event==2) {
2406                                                         if(a) {
2407                                                                 bezt->vec[0][1]= bezt->vec[1][1]= bezt->vec[2][1]= (bezt+1)->vec[1][1];
2408                                                                 if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2409                                                                 if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2410                                                         }
2411                                                 }
2412                                                 else if(event==3) {
2413                                                         bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
2414                                                 }
2415                                                 else if(event==4) {     /* to current frame */
2416                                                         
2417                                                         if(ok2==1 || ok2==2) {
2418                                                                 
2419                                                                 if(G.sipo->blocktype==ID_SEQ) {
2420                                                                         Sequence *seq;
2421                                                         
2422                                                                         seq= (Sequence *)G.sipo->from;
2423                                                                         if(seq) {
2424                                                                                 dx= (float)(CFRA-seq->startdisp);
2425                                                                                 dx= (float)(100.0*dx/((float)(seq->enddisp-seq->startdisp)));
2426                                                                                 
2427                                                                                 dx-= bezt->vec[1][0];
2428                                                                         }
2429                                                                 }
2430                                                                 else dx= G.scene->r.framelen*CFRA - bezt->vec[1][0];
2431                                                                 
2432                                                                 bezt->vec[0][0]+= dx;
2433                                                                 bezt->vec[1][0]+= dx;
2434                                                                 bezt->vec[2][0]+= dx;
2435                                                         }
2436                                                 }
2437                                         }
2438                                         
2439                                         bezt++;
2440                                 }
2441                                 calchandles_ipocurve(ei->icu);
2442                         }
2443                 }
2444         }
2445         editipo_changed(G.sipo, 1);
2446         BIF_undo_push("Snap Ipo");
2447 }
2448
2449
2450
2451 void mouse_select_ipo()
2452 {
2453         Object *ob;
2454         EditIpo *ei, *actei= 0;
2455         IpoCurve *icu;
2456         IpoKey *ik, *actik;
2457         BezTriple *bezt;
2458         Key *key;
2459         KeyBlock *kb, *actkb=0;
2460         float x, y, dist, mindist;
2461         int a, oldflag = 0, hand, ok;
2462         short mval[2], xo, yo;
2463         
2464         if(G.sipo->editipo==0) return;
2465         
2466         get_status_editipo();
2467         
2468         if(G.sipo->showkey) {
2469                 getmouseco_areawin(mval);
2470         
2471                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
2472                 actik= 0;
2473                 mindist= 1000.0;
2474                 ik= G.sipo->ipokey.first;
2475                 while(ik) {
2476                         dist= (float)(fabs(ik->val-x));
2477                         if(ik->flag & 1) dist+= 1.0;
2478                         if(dist < mindist) {
2479                                 actik= ik;
2480                                 mindist= dist;
2481                         }
2482                         ik= ik->next;
2483                 }
2484                 if(actik) {
2485                         oldflag= actik->flag;
2486                         
2487                         if(G.qual & LR_SHIFTKEY);
2488                         else deselectall_editipo();
2489                         
2490                         if(G.qual & LR_SHIFTKEY) {
2491                                 if(oldflag & 1) actik->flag &= ~1;
2492                                 else actik->flag |= 1;
2493                         }
2494                         else {
2495                                 actik->flag |= 1;
2496                         }
2497                 }
2498         }
2499         else if(totipo_edit) {
2500         
2501                 hand= findnearest_ipovert(&icu, &bezt);
2502
2503                 if(G.qual & LR_SHIFTKEY) {
2504                         if(bezt) {
2505                                 if(hand==1) {
2506                                         if(BEZSELECTED(bezt)) {
2507                                                 bezt->f1= bezt->f2= bezt->f3= 0;
2508                                         }
2509                                         else {
2510                                                 bezt->f1= bezt->f2= bezt->f3= 1;
2511                                         }
2512                                 }
2513                                 else if(hand==0) {
2514                                         if(bezt->f1 & 1) bezt->f1= 0;
2515                                         else bezt->f1= 1;
2516                                 }
2517                                 else {
2518                                         if(bezt->f3 & 1) bezt->f3= 0;
2519                                         else bezt->f3= 1;
2520                                 }
2521                         }                               
2522                 }
2523                 else {
2524                         deselectall_editipo();
2525                 
2526                         if(bezt) {
2527                                 if(hand==1) {
2528                                         bezt->f1|= 1; bezt->f2|= 1; bezt->f3|= 1;
2529                                 }
2530                                 else if(hand==0) bezt->f1|= 1;
2531                                 else bezt->f3|= 1;
2532                         }
2533                 }
2534         }
2535         else {
2536                 
2537                 /* vertex keys ? */
2538                 
2539                 if(G.sipo->blocktype==ID_KE && G.sipo->from) {
2540                         key= (Key *)G.sipo->from;
2541                         
2542                         ei= G.sipo->editipo;
2543                         if(key->type==KEY_NORMAL || (ei->flag & IPO_VISIBLE)) {
2544                                 getmouseco_areawin(mval);
2545                                 
2546                                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
2547                                 /* how much is 20 pixels? */
2548                                 mindist= (float)(20.0*(G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)curarea->winy);
2549                                 
2550                                 kb= key->block.first;
2551                                 while(kb) {
2552                                         dist= (float)(fabs(kb->pos-y));
2553                                         if(kb->flag & SELECT) dist+= (float)0.01;
2554                                         if(dist < mindist) {
2555                                                 actkb= kb;
2556                                                 mindist= dist;
2557                                         }
2558                                         kb= kb->next;
2559                                 }
2560                                 if(actkb) {
2561                                         ok= TRUE;
2562                                         if(G.obedit && (actkb->flag & 1)==0) {
2563                                                 ok= okee("Copy key after leaving Edit Mode");
2564                                         }
2565                                         if(ok) {
2566                                                 /* also does all keypos */
2567                                                 deselectall_editipo();
2568                                                 
2569                                                 actkb->flag |= 1;
2570                                                 
2571                                                 /* calc keypos */
2572                                                 showkeypos((Key *)G.sipo->from, actkb);
2573                                         }
2574                                 }
2575                         }
2576                 }
2577                         
2578                 /* select curve */
2579                 if(actkb==0) {
2580                         if(totipo_vis==1) {
2581                                 ei= G.sipo->editipo;
2582                                 for(a=0; a<G.sipo->totipo; a++, ei++) {
2583                                         if(ei->icu) {
2584                                                 if(ei->flag & IPO_VISIBLE) actei= ei;
2585                                         }
2586                                 }
2587                         }
2588                         else if(totipo_vis>1) {
2589                                 actei= select_proj_ipo(0, 0);
2590                         }
2591                         
2592                         if(actei) oldflag= actei->flag;
2593                         
2594                         if(G.qual & LR_SHIFTKEY);
2595                         else deselectall_editipo();
2596                         
2597                         if(actei) {
2598                                 if(G.qual & LR_SHIFTKEY) {
2599                                         if(oldflag & IPO_SELECT) actei->flag &= ~IPO_SELECT;
2600                                         else actei->flag |= IPO_SELECT;
2601                                 }
2602                                 else {
2603                                         actei->flag |= IPO_SELECT;
2604                                 }
2605                         }
2606                 }
2607         }
2608         
2609         update_editipo_flags();
2610         
2611         force_draw(0);
2612         BIF_undo_push("Select Ipo");
2613         
2614         if(G.sipo->showkey && G.sipo->blocktype==ID_OB) {
2615                 ob= OBACT;
2616                 if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
2617         }
2618         
2619         getmouseco_areawin(mval);
2620         xo= mval[0]; 
2621         yo= mval[1];
2622
2623         while(get_mbut()&R_MOUSE) {             
2624                 getmouseco_areawin(mval);
2625                 if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
2626                         
2627                         if(actkb) move_keys();
2628                         else transform_ipo('g');
2629                         
2630                         return;
2631                 }
2632                 BIF_wait_for_statechange();
2633         }
2634 }
2635
2636 int icu_keys_bezier_loop(IpoCurve *icu,
2637                          int (*bezier_function)(BezTriple *),
2638                          void (ipocurve_function)(struct IpoCurve *icu)) 
2639 {
2640     /*  This loops through the beziers in the Ipocurve, and executes 
2641      *  the generic user provided 'bezier_function' on each one. 
2642      *  Optionally executes the generic function ipocurve_function on the 
2643      *  IPO curve after looping (eg. calchandles_ipocurve)
2644      */
2645
2646     int b;
2647     BezTriple *bezt;
2648
2649     b    = icu->totvert;
2650     bezt = icu->bezt;
2651
2652     /* if bezier_function has been specified
2653      * then loop through each bezier executing
2654      * it.
2655      */
2656
2657     if (bezier_function != NULL) {
2658         while(b--) {
2659             /* exit with return code 1 if the bezier function 
2660              * returns 1 (good for when you are only interested
2661              * in finding the first bezier that
2662              * satisfies a condition).
2663              */
2664             if (bezier_function(bezt)) return 1;
2665             bezt++;
2666         }
2667     }
2668
2669     /* if ipocurve_function has been specified 
2670      * then execute it
2671      */
2672     if (ipocurve_function != NULL)
2673         ipocurve_function(icu);
2674
2675     return 0;
2676
2677 }
2678
2679 int ipo_keys_bezier_loop(Ipo *ipo,
2680                          int (*bezier_function)(BezTriple *),
2681                          void (ipocurve_function)(struct IpoCurve *icu))
2682 {
2683     /*  This loops through the beziers that are attached to
2684      *  the selected keys on the Ipocurves of the Ipo, and executes 
2685      *  the generic user provided 'bezier_function' on each one. 
2686      *  Optionally executes the generic function ipocurve_function on a 
2687      *  IPO curve after looping (eg. calchandles_ipocurve)
2688      */
2689
2690     IpoCurve *icu;
2691
2692     /* Loop through each curve in the Ipo
2693      */
2694     for (icu=ipo->curve.first; icu; icu=icu->next){
2695         if (icu_keys_bezier_loop(icu,bezier_function, ipocurve_function))
2696             return 1;
2697     }
2698
2699     return 0;
2700 }
2701
2702 int selected_bezier_loop(int (*looptest)(EditIpo *),
2703                          int (*bezier_function)(BezTriple *),
2704                          void (ipocurve_function)(struct IpoCurve *icu))
2705 {
2706         /*  This loops through the beziers that are attached to
2707          *  selected keys in editmode in the IPO window, and executes 
2708          *  the generic user-provided 'bezier_function' on each one 
2709          *  that satisfies the 'looptest' function. Optionally executes
2710          *  the generic function ipocurve_function on a IPO curve
2711          *  after looping (eg. calchandles_ipocurve)
2712          */
2713
2714         EditIpo *ei;
2715         BezTriple *bezt;
2716         int a, b;
2717
2718         /* Get the first Edit Ipo from the selected Ipos
2719          */
2720         ei= G.sipo->editipo;
2721
2722         /* Loop throught all of the selected Ipo's
2723          */
2724         for(a=0; a<G.sipo->totipo; a++, ei++) {
2725                 /* Do a user provided test on the Edit Ipo
2726                  * to determine whether we want to process it
2727                  */
2728                 if (looptest(ei)) {
2729                         /* Loop through the selected
2730                          * beziers on the Edit Ipo
2731                          */
2732                         bezt = ei->icu->bezt;
2733                         b    = ei->icu->totvert;
2734                         
2735                         /* if bezier_function has been specified
2736                          * then loop through each bezier executing
2737                          * it.
2738                          */
2739                         if (bezier_function != NULL) {
2740                                 while(b--) {
2741                                         /* exit with return code 1 if the bezier function 
2742                                          * returns 1 (good for when you are only interested
2743                                          * in finding the first bezier that
2744                                          * satisfies a condition).
2745                                          */
2746                                         if (bezier_function(bezt)) return 1;
2747                                         bezt++;
2748                                 }
2749                         }
2750
2751                         /* if ipocurve_function has been specified 
2752                          * then execute it
2753                          */
2754                         if (ipocurve_function != NULL)
2755                                 ipocurve_function(ei->icu);
2756                 }
2757                 /* nufte flourdje zim ploopydu <-- random dutch looking comment ;) */
2758                 /* looks more like russian to me! (ton) */
2759         }
2760
2761         return 0;
2762 }
2763
2764 int select_bezier_add(BezTriple *bezt) {
2765   /* Select the bezier triple */
2766   bezt->f1 |= 1;
2767   bezt->f2 |= 1;
2768   bezt->f3 |= 1;
2769   return 0;
2770 }
2771
2772 int select_bezier_subtract(BezTriple *bezt) {
2773   /* Deselect the bezier triple */
2774   bezt->f1 &= ~1;
2775   bezt->f2 &= ~1;
2776   bezt->f3 &= ~1;
2777   return 0;
2778 }
2779
2780 int select_bezier_invert(BezTriple *bezt) {
2781   /* Invert the selection for the bezier triple */
2782   bezt->f2 ^= 1;
2783   if ( bezt->f2 & 1 ) {
2784     bezt->f1 |= 1;
2785     bezt->f3 |= 1;
2786   }
2787   else {
2788     bezt->f1 &= ~1;
2789     bezt->f3 &= ~1;
2790   }
2791   return 0;
2792 }
2793
2794 int set_bezier_auto(BezTriple *bezt) 
2795 {
2796         /* Sets the selected bezier handles to type 'auto' 
2797          */
2798
2799         /* is a handle selected? If so
2800          * set it to type auto
2801          */
2802         if(bezt->f1 || bezt->f3) {
2803                 if(bezt->f1) bezt->h1= 1; /* the secret code for auto */
2804                 if(bezt->f3) bezt->h2= 1;
2805
2806                 /* if the handles are not of the same type, set them
2807                  * to type free
2808                  */
2809                 if(bezt->h1!=bezt->h2) {
2810                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
2811                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
2812                 }
2813         }
2814         return 0;
2815 }
2816
2817 int set_bezier_vector(BezTriple *bezt) 
2818 {
2819         /* Sets the selected bezier handles to type 'vector' 
2820          */
2821
2822         /* is a handle selected? If so
2823          * set it to type vector
2824          */
2825         if(bezt->f1 || bezt->f3) {
2826                 if(bezt->f1) bezt->h1= 2; /* the code for vector */
2827                 if(bezt->f3) bezt->h2= 2;
2828     
2829                 /* if the handles are not of the same type, set them
2830                  * to type free
2831                  */
2832                 if(bezt->h1!=bezt->h2) {
2833                         if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
2834                         if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
2835                 }
2836         }
2837         return 0;
2838 }
2839
2840 int bezier_isfree(BezTriple *bezt) 
2841 {
2842         /* queries whether the handle should be set
2843          * to type 'free' (I think)
2844          */
2845         if(bezt->f1 && bezt->h1) return 1;
2846         if(bezt->f3 && bezt->h2) return 1;
2847         return 0;
2848 }
2849
2850 int set_bezier_free(BezTriple *bezt) 
2851 {
2852         /* Sets selected bezier handles to type 'free' 
2853          */
2854         if(bezt->f1) bezt->h1= HD_FREE;
2855         if(bezt->f3) bezt->h2= HD_FREE;
2856         return 0;
2857 }
2858
2859 int set_bezier_align(BezTriple *bezt) 
2860 {
2861         /* Sets selected bezier handles to type 'align' 
2862          */
2863         if(bezt->f1) bezt->h1= HD_ALIGN;
2864         if(bezt->f3) bezt->h2= HD_ALIGN;
2865         return 0;
2866 }
2867
2868 int vis_edit_icu_bez(EditIpo *ei) {
2869         /* A 4 part test for an EditIpo :
2870          *   is it a) visible
2871          *         b) in edit mode
2872          *         c) does it contain an Ipo Curve
2873          *         d) does that ipo curve have a bezier
2874          *
2875          * (The reason why I don't just use the macro
2876          * is I need a pointer to a function.)
2877          */
2878         return ISPOIN4(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu, icu->bezt);
2879 }
2880
2881 void select_ipo_bezier_keys(Ipo *ipo, int selectmode)
2882 {
2883   /* Select all of the beziers in all
2884    * of the Ipo curves belonging to the
2885    * Ipo, using the selection mode.
2886    */
2887   switch (selectmode) {
2888   case SELECT_ADD:
2889     ipo_keys_bezier_loop(ipo, select_bezier_add, NULL);
2890     break;
2891   case SELECT_SUBTRACT:
2892     ipo_keys_bezier_loop(ipo, select_bezier_subtract, NULL);
2893     break;
2894   case SELECT_INVERT:
2895     ipo_keys_bezier_loop(ipo, select_bezier_invert, NULL);
2896     break;
2897   }
2898 }
2899
2900 void sethandles_ipo_keys(Ipo *ipo, int code)
2901 {
2902         /* this function lets you set bezier handles all to
2903          * one type for some Ipo's (e.g. with hotkeys through
2904          * the action window).
2905          */ 
2906
2907         /* code==1: set autohandle */
2908         /* code==2: set vectorhandle */
2909         /* als code==3 (HD_ALIGN) toggelt het, vectorhandles worden HD_FREE */
2910         
2911         switch(code) {
2912         case 1:
2913                 /*** Set to auto ***/
2914                 ipo_keys_bezier_loop(ipo, set_bezier_auto,
2915                                                          calchandles_ipocurve);
2916                 break;
2917         case 2:
2918                 /*** Set to vector ***/
2919                 ipo_keys_bezier_loop(ipo, set_bezier_vector,
2920                          calchandles_ipocurve);
2921                 break;
2922         default:
2923                 if ( ipo_keys_bezier_loop(ipo, bezier_isfree, NULL) ) {
2924                         /*** Set to free ***/
2925                         ipo_keys_bezier_loop(ipo, set_bezier_free,
2926                            calchandles_ipocurve);
2927                 }
2928                 else {
2929                         /*** Set to align ***/
2930                         ipo_keys_bezier_loop(ipo, set_bezier_align,
2931                            calchandles_ipocurve);
2932                 }
2933                 break;
2934         }
2935
2936
2937 }
2938
2939 void sethandles_ipo(int code)
2940 {
2941         /* this function lets you set bezier handles all to
2942          * one type for some selected keys in edit mode in the
2943          * IPO window (e.g. with hotkeys)
2944          */ 
2945
2946         /* code==1: set autohandle */
2947         /* code==2: set vectorhandle */
2948         /* als code==3 (HD_ALIGN) toggelt het, vectorhandles worden HD_FREE */
2949
2950         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
2951
2952         switch(code) {
2953         case 1:
2954                 /*** Set to auto ***/
2955                 selected_bezier_loop(vis_edit_icu_bez, set_bezier_auto,
2956                          calchandles_ipocurve);
2957                 break;
2958         case 2:
2959                 /*** Set to vector ***/
2960                 selected_bezier_loop(vis_edit_icu_bez, set_bezier_vector,
2961                          calchandles_ipocurve);
2962                 break;
2963         default:
2964                 if (selected_bezier_loop(vis_edit_icu_bez, bezier_isfree, NULL) ) {
2965                         /*** Set to free ***/
2966                         selected_bezier_loop(vis_edit_icu_bez, set_bezier_free,
2967                                                                  calchandles_ipocurve);
2968                 }
2969                 else {
2970                         /*** Set to align ***/
2971                         selected_bezier_loop(vis_edit_icu_bez, set_bezier_align,
2972                                                                  calchandles_ipocurve);
2973                 }
2974                 break;
2975         }
2976
2977         editipo_changed(G.sipo, 1);
2978         BIF_undo_push("Set handles Ipo");
2979 }
2980
2981
2982 void set_ipocurve_constant(struct IpoCurve *icu) {
2983         /* Sets the type of the IPO curve to constant
2984          */
2985         icu->ipo= IPO_CONST;
2986 }
2987
2988 void set_ipocurve_linear(struct IpoCurve *icu) {
2989         /* Sets the type of the IPO curve to linear
2990          */
2991         icu->ipo= IPO_LIN;
2992 }
2993
2994 void set_ipocurve_bezier(struct IpoCurve *icu) {
2995         /* Sets the type of the IPO curve to bezier
2996          */
2997         icu->ipo= IPO_BEZ;
2998 }
2999
3000
3001 void setipotype_ipo(Ipo *ipo, int code)
3002 {
3003         /* Sets the type of the each ipo curve in the
3004          * Ipo to a value based on the code
3005          */
3006         switch (code) {
3007         case 1:
3008                 ipo_keys_bezier_loop(ipo, NULL, set_ipocurve_constant);
3009                 break;
3010         case 2:
3011                 ipo_keys_bezier_loop(ipo, NULL, set_ipocurve_linear);
3012                 break;
3013         case 3:
3014                 ipo_keys_bezier_loop(ipo, NULL, set_ipocurve_bezier);
3015                 break;
3016         }
3017 }
3018
3019 void set_ipotype()
3020 {
3021         EditIpo *ei;
3022         Key *key;
3023         KeyBlock *kb;
3024         int a;
3025         short event;
3026
3027         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
3028         if(G.sipo->showkey) return;
3029         get_status_editipo();
3030         
3031         if(G.sipo->blocktype==ID_KE && totipo_edit==0 && totipo_sel==0) {
3032                 key= (Key *)G.sipo->from;
3033                 if(key==0) return;
3034                 
3035                 event= pupmenu("Key Type %t|Linear %x1|Cardinal %x2|B Spline %x3");
3036                 if(event < 1) return;
3037                 
3038                 kb= key->block.first;
3039                 while(kb) {
3040                         if(kb->flag & SELECT) {
3041                                 kb->type= 0;
3042                                 if(event==1) kb->type= KEY_LINEAR;
3043                                 if(event==2) kb->type= KEY_CARDINAL;
3044                                 if(event==3) kb->type= KEY_BSPLINE;
3045                         }
3046                         kb= kb->next;
3047                 }
3048         }
3049         else {
3050                 event= pupmenu("Ipo Type %t|Constant %x1|Linear %x2|Bezier %x3");
3051                 if(event < 1) return;
3052                 
3053                 ei= G.sipo->editipo;
3054                 for(a=0; a<G.sipo->totipo; a++, ei++) {
3055                         if ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu) {
3056                                 if(event==1) ei->icu->ipo= IPO_CONST;
3057                                 else if(event==2) ei->icu->ipo= IPO_LIN;
3058                                 else ei->icu->ipo= IPO_BEZ;
3059                         }
3060                 }
3061         }
3062         BIF_undo_push("Set ipo type");
3063         scrarea_queue_winredraw(curarea);
3064 }
3065
3066 void borderselect_ipo()
3067 {
3068         EditIpo *ei;
3069         IpoKey *ik;
3070         BezTriple *bezt;
3071         rcti rect;
3072         rctf rectf;
3073         int a, b, val;
3074         short mval[2];
3075
3076         get_status_editipo();
3077         
3078         val= get_border(&rect, 3);
3079
3080         if(val) {
3081                 mval[0]= rect.xmin;
3082                 mval[1]= rect.ymin;
3083                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
3084                 mval[0]= rect.xmax;
3085                 mval[1]= rect.ymax;
3086                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
3087
3088                 if(G.sipo->showkey) {
3089                         ik= G.sipo->ipokey.first;
3090                         while(ik) {
3091                                 if(rectf.xmin<ik->val && rectf.xmax>ik->val) {
3092                                         if(val==LEFTMOUSE) ik->flag |= 1;
3093                                         else ik->flag &= ~1;
3094                                 }
3095                                 ik= ik->next;
3096                         }
3097                         update_editipo_flags();
3098                 }
3099                 else if(totipo_edit==0) {
3100                         if(rect.xmin<rect.xmax && rect.ymin<rect.ymax)
3101                                 select_proj_ipo(&rectf, val);
3102                 }
3103                 else {
3104                         
3105                         ei= G.sipo->editipo;
3106                         for(a=0; a<G.sipo->totipo; a++, ei++) {
3107                                 if ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu) {
3108                                         if(ei->icu->bezt) {
3109                                                 b= ei->icu->totvert;
3110                                                 bezt= ei->icu->bezt;
3111                                                 while(b--) {
3112                                                         int bit= (val==LEFTMOUSE);
3113                                                         
3114                                                         if(BLI_in_rctf(&rectf, bezt->vec[0][0], bezt->vec[0][1]))
3115                                                                 bezt->f1 = (bezt->f1&~1) | bit;
3116                                                         if(BLI_in_rctf(&rectf, bezt->vec[1][0], bezt->vec[1][1]))
3117                                                                 bezt->f2 = (bezt->f2&~1) | bit;
3118                                                         if(BLI_in_rctf(&rectf, bezt->vec[2][0], bezt->vec[2][1]))
3119                                                                 bezt->f3 = (bezt->f3&~1) | bit;
3120
3121                                                         bezt++;
3122                                                 }
3123                                         }
3124                                 }
3125                         }
3126                 }
3127                 BIF_undo_push("Border select Ipo");
3128                 scrarea_queue_winredraw(curarea);
3129         }
3130 }
3131
3132
3133
3134
3135 void del_ipo()
3136 {
3137         EditIpo *ei;
3138         BezTriple *bezt, *bezt1;
3139         int a, b;
3140         int del, event;
3141
3142         get_status_editipo();
3143         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
3144         
3145         if(totipo_edit==0 && totipo_sel==0 && totipo_vertsel==0) {
3146                 delete_key();
3147                 return;
3148         }
3149         
3150         if( okee("Erase selected")==0 ) return;
3151
3152         // eerste doorloop, kunnen hele stukken weg? 
3153         ei= G.sipo->editipo;
3154         for(a=0; a<G.sipo->totipo; a++, ei++) {
3155         
3156                 del= 0;
3157                 
3158                 if(G.sipo->showkey==0 && totipo_edit==0) {
3159                         if ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu) {
3160                                 del= 1;
3161                         }
3162                 }
3163                 else {
3164                         if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
3165                                 if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
3166