Orange branch: Revived hidden treasure, the Groups!
[blender.git] / source / blender / src / editipo.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2005. Full recode
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28
29 /* this code feels over-complex, mostly because I choose in the past to devise a system
30   that converts the Ipo blocks (linked to Object, Material, etc), into a copy of that
31   data which is being worked on;  the 'editipo'.
32   The editipo then can have 'ipokey' data, which is optimized for editing curves as if
33   it were key positions. This is still a great feature to work with, which makes ipo editing
34   in Blender still valuable. However, getting this beast under control was hard, even
35   for me... (ton) */
36
37 #include <stdlib.h>
38 #include <string.h>
39 #include <math.h>
40
41 #ifndef WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #endif   
46 #include "MEM_guardedalloc.h"
47 #include "PIL_time.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_arithb.h"
51
52 #include "DNA_constraint_types.h"
53 #include "DNA_action_types.h"
54 #include "DNA_armature_types.h"
55 #include "DNA_camera_types.h"
56 #include "DNA_curve_types.h"
57 #include "DNA_group_types.h"
58 #include "DNA_ipo_types.h"
59 #include "DNA_key_types.h"
60 #include "DNA_lamp_types.h"
61 #include "DNA_material_types.h"
62 #include "DNA_object_types.h"
63 #include "DNA_screen_types.h"
64 #include "DNA_scene_types.h"
65 #include "DNA_space_types.h"
66 #include "DNA_sequence_types.h"
67 #include "DNA_sound_types.h"
68 #include "DNA_texture_types.h"
69 #include "DNA_userdef_types.h"
70 #include "DNA_view3d_types.h"
71 #include "DNA_world_types.h"
72
73 #include "BKE_action.h"
74 #include "BKE_anim.h"
75 #include "BKE_constraint.h"
76 #include "BKE_depsgraph.h"
77 #include "BKE_global.h"
78 #include "BKE_group.h"
79 #include "BKE_ipo.h"
80 #include "BKE_key.h"
81 #include "BKE_material.h"
82 #include "BKE_texture.h"
83 #include "BKE_utildefines.h"
84
85 #include "BIF_butspace.h"
86 #include "BIF_editaction.h"
87 #include "BIF_editconstraint.h"
88 #include "BIF_editkey.h"
89 #include "BIF_editnla.h"
90 #include "BIF_editseq.h"
91 #include "BIF_editview.h"
92 #include "BIF_interface.h"
93 #include "BIF_mywindow.h"
94 #include "BIF_poseobject.h"
95 #include "BIF_screen.h"
96 #include "BIF_space.h"
97 #include "BIF_toolbox.h"
98 #include "BIF_poseobject.h"
99
100 #include "BDR_drawobject.h"
101 #include "BDR_editobject.h"
102
103 #include "BSE_trans_types.h"
104 #include "BSE_editipo_types.h"
105 #include "BSE_drawipo.h"
106 #include "BSE_editipo.h"
107 #include "BSE_edit.h"
108 #include "BSE_drawview.h"
109 #include "BSE_headerbuttons.h"
110
111 #include "blendef.h"
112 #include "mydevice.h"
113
114 extern int ob_ar[];
115 extern int ma_ar[];
116 extern int seq_ar[];
117 extern int cu_ar[];
118 extern int wo_ar[];
119 extern int la_ar[];
120 extern int cam_ar[];
121 extern int snd_ar[];
122 extern int ac_ar[];
123 extern int co_ar[];
124 extern int te_ar[];
125
126 /* forwards */
127 #define BEZSELECTED(bezt)   (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1))
128
129 #define IPOTHRESH       0.9
130 #define ISPOIN(a, b, c)                       ( (a->b) && (a->c) )
131 #define ISPOIN3(a, b, c, d)           ( (a->b) && (a->c) && (a->d) )
132
133 /* tests if only one editipo is active */
134 static void check_active_editipo(void)
135 {
136         EditIpo *ei, *actei;
137         int a;
138         
139         actei= G.sipo->editipo;
140         if(actei) {
141                 for(a=0; a<G.sipo->totipo; a++, actei++) {
142                         if(actei->flag & IPO_ACTIVE) 
143                                 break;
144                 }
145                 if(actei==NULL) {
146                         /* set visible active */
147                         for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
148                                 if(ei->flag & IPO_VISIBLE)
149                                         break;
150                         }
151                         if(ei==NULL) ei=G.sipo->editipo;
152                         ei->flag |= IPO_ACTIVE;
153                         if(ei->icu) ei->icu->flag |= IPO_ACTIVE;
154                 }
155                 else {
156                         /* make sure no others are active */
157                         for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
158                                 if(ei!=actei) {
159                                         ei->flag &= ~IPO_ACTIVE;
160                                         if(ei->icu) ei->icu->flag &= ~IPO_ACTIVE;
161                                 }
162                         }
163                 }
164         }
165 }
166
167 /* sets this ei channel active */
168 static void set_active_editipo(EditIpo *actei)
169 {
170         EditIpo *ei;
171         int a;
172         
173         for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
174                 ei->flag &= ~IPO_ACTIVE;
175                 if(ei->icu) ei->icu->flag &= ~IPO_ACTIVE;
176         }
177         actei->flag |= IPO_ACTIVE;
178         if(actei->icu) actei->icu->flag |= IPO_ACTIVE;
179 }
180
181 EditIpo *get_active_editipo(void)
182 {
183         EditIpo *ei;
184         int a;
185         
186         if(G.sipo==NULL)
187                 return NULL;
188         
189         for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++)
190                 if(ei->flag & IPO_ACTIVE)
191                         return ei;
192         
193         return NULL;
194 }
195
196 static void set_active_key(int index)
197 {
198         if(G.sipo->blocktype==ID_KE && G.sipo->from) {
199                 Object *ob= (Object *)G.sipo->from;
200                 Key *key= ob_get_key(ob);
201                 
202                 if(key) {
203                         KeyBlock *curkb;
204                         
205                         curkb= BLI_findlink(&key->block, index-1);
206                         if(curkb) {
207                                 ob->shapenr= index;
208                                 ob->shapeflag |= OB_SHAPE_TEMPLOCK;
209                                 
210                                 /* calc keypos */
211                                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
212                                 allqueue(REDRAWVIEW3D, 0);
213                                 allqueue(REDRAWBUTSEDIT, 0);
214                         }
215                 }
216         }                       
217 }
218
219 void editipo_changed(SpaceIpo *si, int doredraw)
220 {
221         EditIpo *ei;
222         View2D *v2d;
223         Key *key;
224         KeyBlock *kb;
225         int a, first=1;
226
227         ei= si->editipo;
228         if(ei==0)
229                 return;
230         
231         for(a=0; a<si->totipo; a++, ei++) {
232                 
233                 if(ei->icu) {
234                         
235                                 /* twice because of ittererating new autohandle */
236                         calchandles_ipocurve(ei->icu);
237                         calchandles_ipocurve(ei->icu);
238                         
239                         if(ei->flag & IPO_VISIBLE) {
240                 
241                                 boundbox_ipocurve(ei->icu);
242                                 sort_time_ipocurve(ei->icu);
243                                 if(first) {
244                                         si->v2d.tot= ei->icu->totrct;
245                                         first= 0;
246                                 }
247                                 else BLI_union_rctf(&(si->v2d.tot), &(ei->icu->totrct));
248                         }
249                 }
250         }
251         
252
253         v2d= &(si->v2d);        
254
255         /* keylines? */
256         if(si->blocktype==ID_KE) {
257                 key= ob_get_key((Object *)G.sipo->from);
258                 if(key && key->block.first) {
259                         kb= key->block.first;
260                         if(kb->pos < v2d->tot.ymin) v2d->tot.ymin= kb->pos;
261                         kb= key->block.last;
262                         if(kb->pos > v2d->tot.ymax) v2d->tot.ymax= kb->pos;
263                 }
264         }
265         
266         /* is there no curve? */
267         if(first) {
268                 v2d->tot.xmin= 0.0;
269                 v2d->tot.xmax= EFRA;
270                 v2d->tot.ymin= (float)-0.1;
271                 v2d->tot.ymax= (float)1.1;
272         
273                 if(si->blocktype==ID_SEQ) {
274                         v2d->tot.xmin= -5.0;
275                         v2d->tot.xmax= 105.0;
276                         v2d->tot.ymin= (float)-0.1;
277                         v2d->tot.ymax= (float)1.1;
278                 }
279         }
280         
281         si->tot= v2d->tot;      
282         
283         if(doredraw) {
284                 /* if you always call do_ipo: you get problems with insertkey, for example
285                  * when inserting only a 'loc' the 'ob->rot' value then is changed.
286                  */
287
288                 if(si->blocktype==ID_OB) {                      
289                                 /* clear delta loc,rot,size (when free/delete ipo) */
290                         clear_delta_obipo(si->ipo);
291                         
292                 }
293         
294                 do_ipo(si->ipo);
295
296                 allqueue(REDRAWIPO, 0);
297                 allqueue(REDRAWACTION, 0);
298                 allqueue(REDRAWTIME, 0);
299                 allqueue(REDRAWNLA, 0);
300                 allqueue(REDRAWBUTSOBJECT, 0);
301                 
302                 if(si->blocktype==ID_OB) {
303                         Object *ob= (Object *)si->from;                 
304                         if(ob) DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
305                         allqueue(REDRAWVIEW3D, 0);
306                         allqueue(REDRAWNLA, 0);
307                 }
308
309                 else if(si->blocktype==ID_MA) allqueue(REDRAWBUTSSHADING, 0);
310                 else if(si->blocktype==ID_TE) allqueue(REDRAWBUTSSHADING, 0);
311                 else if(si->blocktype==ID_WO) allqueue(REDRAWBUTSSHADING, 0);
312                 else if(si->blocktype==ID_LA) allqueue(REDRAWBUTSSHADING, 0);
313 //              else if(si->blocktype==ID_SO) allqueue(REDRAWBUTSSOUND, 0);
314                 else if(si->blocktype==ID_CA) {
315                         allqueue(REDRAWBUTSEDIT, 0);
316                         allqueue(REDRAWVIEW3D, 0);
317                 }
318                 else if(si->blocktype==ID_SEQ) clear_last_seq();
319                 else if(si->blocktype==ID_PO) {
320                         Object *ob= OBACT;
321                         if(ob && ob->pose) {
322                                 DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
323                         }
324                         allqueue(REDRAWVIEW3D, 0);
325                         allqueue(REDRAWACTION, 0);
326                         allqueue(REDRAWNLA, 0);
327                 }
328                 else if(si->blocktype==ID_KE) {
329                         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
330                         allqueue(REDRAWVIEW3D, 0);
331                 }
332                 else if(si->blocktype==ID_CU) {
333                         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
334                         allqueue(REDRAWVIEW3D, 0);
335                 }
336         }
337
338         if(si->showkey) make_ipokey();
339         
340         if(si->actname[0])
341                 synchronize_action_strips();
342 }
343
344 void scale_editipo(void)
345 {
346         /* comes from buttons, scale with G.sipo->tot rect */
347         
348         EditIpo *ei;
349         BezTriple *bezt;
350         float facx, facy;
351         int a, b;       
352         
353         facx= (G.sipo->tot.xmax-G.sipo->tot.xmin)/(G.sipo->v2d.tot.xmax-G.sipo->v2d.tot.xmin);
354         facy= (G.sipo->tot.ymax-G.sipo->tot.ymin)/(G.sipo->v2d.tot.ymax-G.sipo->v2d.tot.ymin);
355
356         ei= G.sipo->editipo;
357         if(ei==0) return;
358         for(a=0; a<G.sipo->totipo; a++, ei++) {
359                 if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
360                         bezt= ei->icu->bezt;
361                         b= ei->icu->totvert;
362                         while(b--) {
363                                 
364                                 bezt->vec[0][0]= facx*(bezt->vec[0][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
365                                 bezt->vec[1][0]= facx*(bezt->vec[1][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
366                                 bezt->vec[2][0]= facx*(bezt->vec[2][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
367                         
368                                 bezt->vec[0][1]= facy*(bezt->vec[0][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
369                                 bezt->vec[1][1]= facy*(bezt->vec[1][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
370                                 bezt->vec[2][1]= facy*(bezt->vec[2][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
371
372                                 bezt++;
373                         }
374                 }
375         }
376
377         editipo_changed(G.sipo, 1);
378
379         BIF_undo_push("Scale Edit Ipo");
380         allqueue(REDRAWNLA, 0);
381         allqueue (REDRAWACTION, 0);
382         allqueue(REDRAWIPO, 0);
383 }
384
385 static void make_ob_editipo(Object *ob, SpaceIpo *si)
386 {
387         EditIpo *ei;
388         int a, len, colipo=0;
389         char *name;
390         
391         if(ob->type==OB_MESH) colipo= 1;
392
393         ei= si->editipo= MEM_callocN(OB_TOTIPO*sizeof(EditIpo), "editipo");
394         
395         si->totipo= OB_TOTIPO;
396         
397         for(a=0; a<OB_TOTIPO; a++) {
398                 name = getname_ob_ei(ob_ar[a], colipo);
399                 strcpy(ei->name, name);
400                 ei->adrcode= ob_ar[a];
401                 
402                 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;
403                 else if(ei->adrcode==OB_LAY) ei->disptype= IPO_DISPBITS;
404                 else if(ei->adrcode==OB_TIME) ei->disptype= IPO_DISPTIME;
405
406                 ei->col= ipo_rainbow(a, OB_TOTIPO);
407
408                 if(colipo) {
409                         len= strlen(ei->name);
410                         if(len) {
411                                 if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
412                                 else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
413                                 else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
414                         }
415                 }
416                 
417                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
418                 if(ei->icu) {
419                         ei->flag= ei->icu->flag;
420                 }
421                 
422                 
423                 ei++;
424         }
425 }
426
427 static void make_seq_editipo(SpaceIpo *si)
428 {
429         EditIpo *ei;
430         int a;
431         char *name;
432         
433         ei= si->editipo= MEM_callocN(SEQ_TOTIPO*sizeof(EditIpo), "editipo");
434         
435         si->totipo= SEQ_TOTIPO;
436         
437         
438         for(a=0; a<SEQ_TOTIPO; a++) {
439                 name = getname_seq_ei(seq_ar[a]);
440                 strcpy(ei->name, name);
441                 ei->adrcode= seq_ar[a];
442                 
443                 ei->col= ipo_rainbow(a, SEQ_TOTIPO);
444                 
445                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
446                 if(ei->icu) {
447                         ei->flag= ei->icu->flag;
448                 }
449                 else ei->flag |= IPO_VISIBLE;
450                 
451                 ei++;
452         }
453 }
454
455 static void make_cu_editipo(SpaceIpo *si)
456 {
457         EditIpo *ei;
458         int a;
459         char *name;
460         
461         ei= si->editipo= MEM_callocN(CU_TOTIPO*sizeof(EditIpo), "editipo");
462         
463         si->totipo= CU_TOTIPO;
464         
465         
466         for(a=0; a<CU_TOTIPO; a++) {
467                 name = getname_cu_ei(cu_ar[a]);
468                 strcpy(ei->name, name);
469                 ei->adrcode= cu_ar[a];
470                 
471                 ei->col= ipo_rainbow(a, CU_TOTIPO);
472                 
473                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
474                 if(ei->icu) {
475                         ei->flag= ei->icu->flag;
476                 }
477                 else ei->flag |= IPO_VISIBLE;
478                  
479                 ei++;
480         }
481 }
482
483 static void make_key_editipo(SpaceIpo *si)
484 {
485         Key *key;
486         KeyBlock *kb=NULL;
487         EditIpo *ei;
488         int a;
489         
490         key= ob_get_key((Object *)G.sipo->from);
491         if(key==NULL) return;
492         
493         si->totipo= BLI_countlist(&key->block);
494         ei= si->editipo= MEM_callocN(si->totipo*sizeof(EditIpo), "editipo");
495         
496         for(a=0; a<si->totipo; a++, ei++) {
497                 /* we put refkey first, the rest in order of list */
498                 if(a==0) kb= key->refkey;
499                 else {
500                         if(a==1) 
501                                 kb= key->block.first;
502                         else 
503                                 kb= kb->next;
504                         if(kb==key->refkey)
505                                 kb= kb->next;
506                 }
507
508                 if(kb->name[0] != 0) strncpy(ei->name, kb->name, 31);   // length both same
509                 ei->adrcode= kb->adrcode;
510                 
511                 ei->col= ipo_rainbow(a, KEY_TOTIPO);
512                 
513                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
514                 if(ei->icu) {
515                         ei->flag= ei->icu->flag;
516                 }
517                 else if(a==0) 
518                         if(key && key->type==KEY_NORMAL)
519                                 ei->flag |= IPO_VISIBLE;
520                 
521                 /* active ipo is tied to active shape  */
522                 {
523                         Object *ob= OBACT;
524                         if(a==ob->shapenr-1)
525                                 set_active_editipo(ei);
526                 }
527         }
528         
529         ei= si->editipo;
530         if(key && key->type==KEY_RELATIVE) {
531                 strcpy(ei->name, "----");
532         }
533         else {
534                 ei->flag |= IPO_VISIBLE;
535         }
536 }
537
538 static void make_mat_editipo(SpaceIpo *si)
539 {
540         EditIpo *ei;
541         int a, len;
542         char *name;
543         
544         if(si->from==0) return;
545         
546         ei= si->editipo= MEM_callocN(MA_TOTIPO*sizeof(EditIpo), "editipo");
547         
548         si->totipo= MA_TOTIPO;
549         
550         for(a=0; a<MA_TOTIPO; a++) {
551                 name = getname_mat_ei(ma_ar[a]);
552                 strcpy(ei->name, name);
553                 ei->adrcode= ma_ar[a];
554                 
555                 if(ei->adrcode & MA_MAP1) {
556                         ei->adrcode-= MA_MAP1;
557                         ei->adrcode |= texchannel_to_adrcode(si->channel);
558                 }
559                 else {
560                         if(ei->adrcode==MA_MODE) ei->disptype= IPO_DISPBITS;
561                 }
562                 
563                 ei->col= ipo_rainbow(a, MA_TOTIPO);
564                 
565                 len= strlen(ei->name);
566                 if(len) {
567                         if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
568                         else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
569                         else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
570                 }
571                 
572                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
573                 if(ei->icu) {
574                         ei->flag= ei->icu->flag;
575                 }
576                 
577                 ei++;
578         }
579 }
580
581 static void make_texture_editipo(SpaceIpo *si)
582 {
583         EditIpo *ei;
584         int a;
585         char *name;
586         
587         if(si->from==0) return;    
588         
589         ei= si->editipo= MEM_callocN(TE_TOTIPO*sizeof(EditIpo), "editipo");
590         
591         si->totipo= TE_TOTIPO;
592         
593         for(a=0; a<TE_TOTIPO; a++) {
594                 name = getname_tex_ei(te_ar[a]);
595                 strcpy(ei->name, name);
596                         ei->adrcode= te_ar[a];
597
598                 ei->col= ipo_rainbow(a, TE_TOTIPO);
599                 
600                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
601                 if(ei->icu) {
602                         ei->flag= ei->icu->flag;
603                 }
604                 
605                 ei++;
606         }
607 }
608
609 static void make_world_editipo(SpaceIpo *si)
610 {
611         EditIpo *ei;
612         int a, len;
613         char *name;
614         
615         if(si->from==0) return;
616         
617         ei= si->editipo= MEM_callocN(WO_TOTIPO*sizeof(EditIpo), "editipo");
618         
619         si->totipo= WO_TOTIPO;
620         
621         for(a=0; a<WO_TOTIPO; a++) {
622                 name = getname_world_ei(wo_ar[a]);
623                 
624                 strcpy(ei->name, name); 
625                 ei->adrcode= wo_ar[a];
626                 
627                 if(ei->adrcode & MA_MAP1) {
628                         ei->adrcode-= MA_MAP1;
629                         ei->adrcode |= texchannel_to_adrcode(si->channel);
630                 }
631                 else {
632                         if(ei->adrcode==MA_MODE) ei->disptype= IPO_DISPBITS;
633                 }
634                 
635                 ei->col= ipo_rainbow(a, WO_TOTIPO);
636                 
637                 len= strlen(ei->name);
638                 if(len) {
639                         if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
640                         else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
641                         else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
642                 }
643                 
644                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
645                 if(ei->icu) {
646                         ei->flag= ei->icu->flag;
647                 }
648                 
649                 ei++;
650         }
651 }
652
653 static void make_lamp_editipo(SpaceIpo *si)
654 {
655         EditIpo *ei;
656         int a;
657         char *name;
658         
659         ei= si->editipo= MEM_callocN(LA_TOTIPO*sizeof(EditIpo), "editipo");
660         
661         si->totipo= LA_TOTIPO;
662         
663         for(a=0; a<LA_TOTIPO; a++) {
664                 name = getname_la_ei(la_ar[a]);
665                 strcpy(ei->name, name);
666                 ei->adrcode= la_ar[a];
667
668                 if(ei->adrcode & MA_MAP1) {
669                         ei->adrcode-= MA_MAP1;
670                         ei->adrcode |= texchannel_to_adrcode(si->channel);
671                 }
672
673                 ei->col= ipo_rainbow(a, LA_TOTIPO);
674                 
675                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
676                 if(ei->icu) {
677                         ei->flag= ei->icu->flag;
678                 }
679                 
680                 ei++;
681         }
682 }
683
684 static void make_camera_editipo(SpaceIpo *si)
685 {
686         EditIpo *ei;
687         int a;
688         char *name;
689         
690         ei= si->editipo= MEM_callocN(CAM_TOTIPO*sizeof(EditIpo), "editipo");
691         
692         si->totipo= CAM_TOTIPO;
693         
694         
695         for(a=0; a<CAM_TOTIPO; a++) {
696                 name = getname_cam_ei(cam_ar[a]);
697                 strcpy(ei->name, name);
698                 ei->adrcode= cam_ar[a];
699
700                 ei->col= ipo_rainbow(a, CAM_TOTIPO);
701                 
702                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
703                 if(ei->icu) {
704                         ei->flag= ei->icu->flag;
705                 }
706                 
707                 ei++;
708         }
709 }
710
711 static int make_constraint_editipo(Ipo *ipo, EditIpo **si)
712 {
713         EditIpo *ei;
714         int a;
715         char *name;
716         
717         ei= *si= MEM_callocN(CO_TOTIPO*sizeof(EditIpo), "editipo");
718         
719         for(a=0; a<CO_TOTIPO; a++) {
720                 name = getname_co_ei(co_ar[a]);
721                 strcpy(ei->name, name);
722                 ei->adrcode= co_ar[a];
723
724                 ei->col= ipo_rainbow(a, CO_TOTIPO);
725                 
726                 ei->icu= find_ipocurve(ipo, ei->adrcode);
727                 if(ei->icu) {
728                         ei->flag= ei->icu->flag;
729                 }
730                 
731                 ei++;
732         }
733
734         return CO_TOTIPO;
735 }
736
737 static int make_bone_editipo(Ipo *ipo, EditIpo **si)
738 {
739         EditIpo *ei;
740         int a;
741         char *name;
742         
743         ei= *si= MEM_callocN(AC_TOTIPO*sizeof(EditIpo), "editipo");
744         
745         for(a=0; a<AC_TOTIPO; a++) {
746                 name = getname_ac_ei(ac_ar[a]);
747                 strcpy(ei->name, name);
748                 ei->adrcode= ac_ar[a];
749
750                 ei->col= ipo_rainbow(a, AC_TOTIPO);
751                 
752                 ei->icu= find_ipocurve(ipo, ei->adrcode);
753                 if(ei->icu) {
754                         ei->flag= ei->icu->flag;
755                 }
756                 
757                 ei++;
758         }
759
760         return AC_TOTIPO;
761 }
762
763 static void make_sound_editipo(SpaceIpo *si)
764 {
765         EditIpo *ei;
766         int a;
767         char *name;
768         
769         ei= si->editipo= MEM_callocN(SND_TOTIPO*sizeof(EditIpo), "editipo");
770         
771         si->totipo= SND_TOTIPO;
772         
773         
774         for(a=0; a<SND_TOTIPO; a++) {
775                 name = getname_snd_ei(snd_ar[a]);
776                 strcpy(ei->name, name);
777                 ei->adrcode= snd_ar[a];
778
779                 ei->col= ipo_rainbow(a, SND_TOTIPO);
780                 
781                 ei->icu= find_ipocurve(si->ipo, ei->adrcode);
782                 if(ei->icu) {
783                         ei->flag= ei->icu->flag;
784                 }
785                 
786                 ei++;
787         }
788 }
789
790 /* only called in test_editipo() below */
791 static void make_editipo(void)
792 {
793         EditIpo *ei;
794         Object *ob;
795         rctf *rf;
796         int a;
797
798         if(G.sipo->editipo)
799                 MEM_freeN(G.sipo->editipo);
800         
801         G.sipo->editipo= NULL;
802         G.sipo->totipo= 0;
803         
804         if(G.sipo->from==NULL) return;
805         
806         ob= OBACT;
807
808         if(G.sipo->ipo) G.sipo->showkey= G.sipo->ipo->showkey;
809
810         if(G.sipo->blocktype==ID_SEQ) {
811                 make_seq_editipo(G.sipo);
812         }
813         else if(G.sipo->blocktype==ID_WO) {
814                 make_world_editipo(G.sipo);
815         } 
816         else if(G.sipo->blocktype==ID_OB) {
817                 if (ob) {
818                         ob->ipowin= ID_OB;
819                         make_ob_editipo(ob, G.sipo);
820                 }
821         }
822         else if(G.sipo->blocktype==ID_MA) {
823                 if (ob) {
824                         ob->ipowin= ID_MA;
825                         make_mat_editipo(G.sipo);
826                 }
827         }
828         else if(G.sipo->blocktype==ID_CU) {
829                 if (ob) {
830                         ob->ipowin= ID_CU;
831                         make_cu_editipo(G.sipo);
832                 }
833         }
834         else if(G.sipo->blocktype==ID_KE) {
835                 if (ob) {
836                         ob->ipowin= ID_KE;
837                         make_key_editipo(G.sipo);
838                 }
839         }
840         else if(G.sipo->blocktype==ID_LA) {
841                 if (ob) {
842                         ob->ipowin= ID_LA;
843                         make_lamp_editipo(G.sipo);
844                 }
845         }
846         else if(G.sipo->blocktype==ID_TE) {
847                 if (ob) {
848                         ob->ipowin= ID_TE;
849                         make_texture_editipo(G.sipo);
850                 }
851         }
852         else if(G.sipo->blocktype==ID_CA) {
853                 if (ob) {
854                         ob->ipowin= ID_CA;
855                         make_camera_editipo(G.sipo);
856                 }
857         }
858         else if(G.sipo->blocktype==ID_SO) {
859                 if (ob) {
860                         ob->ipowin= ID_SO;
861                         make_sound_editipo(G.sipo);
862                 }
863         }
864         else if(G.sipo->blocktype==ID_CO){
865                 G.sipo->totipo = make_constraint_editipo(G.sipo->ipo, (EditIpo**)&G.sipo->editipo);
866                 if (ob) {
867                         ob->ipowin= ID_CO;
868                 }
869         }
870         else if(G.sipo->blocktype==ID_PO) {
871
872                 G.sipo->totipo = make_bone_editipo(G.sipo->ipo, (EditIpo**)&G.sipo->editipo);
873                 if (ob) {
874                         ob->ipowin= ID_PO;
875                 }
876         }
877
878         if(G.sipo->editipo==0) return;
879         
880         ei= G.sipo->editipo;
881         for(a=0; a<G.sipo->totipo; a++, ei++) {
882                 if(ei->icu) ei->icu->flag= ei->flag;
883         }
884         editipo_changed(G.sipo, 0);
885         
886         if(G.sipo->ipo) {
887
888                 if (G.sipo->pin)
889                         rf= &(G.sipo->v2d.cur);
890                 else
891                         rf= &(G.sipo->ipo->cur);
892                 
893                 if(rf->xmin<rf->xmax && rf->ymin<rf->ymax) G.v2d->cur= *rf;
894                 else ipo_default_v2d_cur(G.sipo->blocktype, &G.v2d->cur);
895         }
896         else {
897                 ipo_default_v2d_cur(G.sipo->blocktype, &G.v2d->cur);
898         }
899         
900         view2d_do_locks(curarea, V2D_LOCK_COPY);
901 }
902
903 /* evaluates context in the current UI */
904 /* blocktype is type of ipo */
905 /* from is the base pointer to find data to change (ob in case of action or pose) */
906 static void get_ipo_context(short blocktype, ID **from, Ipo **ipo, char *actname, char *constname)
907 {
908         Object *ob= OBACT;
909         
910         *from= NULL;
911         *ipo= NULL;
912         
913         if(blocktype==ID_CO) {
914                 if (ob) {
915                         bConstraintChannel *chan;
916                         bConstraint *con= get_active_constraint(ob);
917                         
918                         if(con) {
919                                 BLI_strncpy(constname, con->name, 32);
920                                 
921                                 chan= get_active_constraint_channel(ob);
922                                 if(chan) {
923                                         *ipo= chan->ipo;
924                                         BLI_strncpy(constname, con->name, 32);
925                                 }
926                                 
927                                 *from= &ob->id;
928                                 
929                                 /* set actname if in posemode */
930                                 if(ob->action) {
931                                         if(ob->flag & OB_POSEMODE) {
932                                                 bPoseChannel *pchan= get_active_posechannel(ob);
933                                                 if(pchan)
934                                                         BLI_strncpy(actname, pchan->name, 32);
935                                         }
936                                         else if(ob->ipoflag & OB_ACTION_OB)
937                                                 strcpy(actname, "Object");
938                                 }
939                         }
940                 }
941         }
942         else if(blocktype==ID_PO) {
943                 if (ob && ob->action && ob->type==OB_ARMATURE) {
944                         bPoseChannel *pchan= get_active_posechannel(ob);
945                         
946                         *from= (ID *)ob;
947                         if (pchan) {
948                                 bActionChannel *achan;
949                                 
950                                 BLI_strncpy(actname, pchan->name, 32);  /* also set when no channel yet */
951                                 
952                                 achan= get_action_channel(ob->action, pchan->name);
953                                 if(achan)
954                                         *ipo= achan->ipo;
955                         }
956                 } 
957                 
958         }
959         else if(blocktype==ID_OB) {
960                 if(ob) {
961                         *from= (ID *)ob;
962                         if(ob->ipoflag & OB_ACTION_OB) {
963                                 if (ob->action) {
964                                         bActionChannel *achan= get_action_channel(ob->action, "Object");
965                                         if(achan) {
966                                                 *ipo= achan->ipo;
967                                                 BLI_strncpy(actname, achan->name, 32);
968                                         }
969                                 }
970                         }
971                         else {
972                                 *ipo= ob->ipo;
973                         }
974                 }
975         }
976         else if(blocktype==ID_SEQ) {
977                 extern Sequence *last_seq;
978                 
979                 if(last_seq && (last_seq->type & SEQ_EFFECT)) {
980                         *from= (ID *)last_seq;
981                         *ipo= last_seq->ipo;
982                 }
983         }
984         else if(blocktype==ID_WO) {
985                 World *wo= G.scene->world;
986                 *from= (ID *)wo;
987                 if(wo) *ipo= wo->ipo;
988         }
989         else if(blocktype==ID_TE) {
990                 if(ob) {
991                         Tex *tex= give_current_texture(ob, ob->actcol);
992                         *from= (ID *)tex;
993                         if(tex) *ipo= tex->ipo;
994                 }
995         }
996         else if(blocktype==ID_MA) {
997                 if(ob) {
998                         Material *ma= give_current_material(ob, ob->actcol);
999                         *from= (ID *)ma;
1000                         if(ma) *ipo= ma->ipo;
1001                 }
1002         }
1003         else if(blocktype==ID_KE) {
1004                 if(ob) {
1005                         Key *key= ob_get_key(ob);
1006                         
1007                         if(ob->ipoflag & OB_ACTION_KEY) {
1008                                 if (ob->action) {
1009                                         bActionChannel *achan= get_action_channel(ob->action, "Shape");
1010                                         if(achan) {
1011                                                 *ipo= achan->ipo;
1012                                                 BLI_strncpy(actname, achan->name, 32);
1013                                         }
1014                                 }
1015                         }
1016                         else if(key) *ipo= key->ipo;
1017                         
1018                         *from= (ID *)ob;
1019                 }
1020         }
1021         else if(blocktype==ID_CU) {
1022                 if(ob && ob->type==OB_CURVE) {
1023                         Curve *cu= ob->data;
1024                         *from= (ID *)cu;
1025                         *ipo= cu->ipo;
1026                 }
1027         }
1028         else if(blocktype==ID_LA) {
1029                 if(ob && ob->type==OB_LAMP) {
1030                         Lamp *la= ob->data;
1031                         *from= (ID *)la;
1032                         *ipo= la->ipo;
1033                 }
1034         }
1035         else if(blocktype==ID_CA) {
1036                 if(ob && ob->type==OB_CAMERA) {
1037                         Camera *ca= ob->data;
1038                         *from= (ID *)ca;
1039                         if(ca) *ipo= ca->ipo;
1040                 }
1041         }
1042         else if(blocktype==ID_SO) {
1043                 
1044                 //              if (G.buts && G.buts->mainb == BUTS_SOUND) {
1045                 //                      bSound *sound = G.buts->lockpoin;
1046                 //                      *from= (ID *)sound;
1047                 //                      if(sound) *ipo= sound->ipo;
1048                 //              }
1049         }
1050 }
1051
1052 /* called on each redraw, check if editipo data has to be remade */
1053 /* if doit already set, it always makes (in case no ipo exists, we need to see the channels */
1054 void test_editipo(int doit)
1055 {
1056         
1057         if(G.sipo->pin==0) {
1058                 Ipo *ipo;
1059                 ID *from;
1060                 char actname[32]="", constname[32]="";
1061                 
1062                 get_ipo_context(G.sipo->blocktype, &from, &ipo, actname, constname);
1063                 
1064                 if(G.sipo->ipo != ipo) {
1065                         G.sipo->ipo= ipo;
1066                         if(ipo) G.v2d->cur= ipo->cur;
1067                         doit= 1;
1068                 }
1069                 if(G.sipo->from != from) {
1070                         G.sipo->from= from;
1071                         doit= 1;
1072                 }
1073                 if( strcmp(G.sipo->actname, actname)) {
1074                         BLI_strncpy(G.sipo->actname, actname, 32);
1075                         doit= 1;
1076                 }
1077                 if( strcmp(G.sipo->constname, constname)) {
1078                         BLI_strncpy(G.sipo->constname, constname, 32);
1079                         doit= 1;
1080                 }
1081                 
1082                 if(G.sipo->ipo)
1083                         G.sipo->ipo->cur = G.v2d->cur;
1084                 
1085         }
1086                 
1087         if(G.sipo->editipo==NULL || doit) {
1088                 make_editipo();
1089         }
1090 }
1091
1092 /* ****************** EditIpo ************************ */
1093
1094 int totipo_edit, totipo_sel, totipo_curve, totipo_vis, totipo_vert, totipo_vertsel, totipo_key, totipo_keysel;
1095
1096 void get_status_editipo(void)
1097 {
1098         EditIpo *ei;
1099         IpoKey *ik;
1100         BezTriple *bezt;
1101         int a, b;
1102         
1103         totipo_vis= 0;
1104         totipo_curve= 0;
1105         totipo_sel= 0;
1106         totipo_edit= 0;
1107         totipo_vert= 0;
1108         totipo_vertsel= 0;
1109         totipo_key= 0;
1110         totipo_keysel= 0;
1111         
1112         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1113         
1114         ei= G.sipo->editipo;
1115         if(ei==0) return;
1116         for(a=0; a<G.sipo->totipo; a++) {
1117                 if( ei->flag & IPO_VISIBLE ) {
1118                         totipo_vis++;
1119                         if(ei->flag & IPO_SELECT) totipo_sel++;
1120                         if(ei->icu && ei->icu->totvert) totipo_curve++;
1121                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
1122                                 
1123                                 /* if showkey: do count the vertices (for grab) */
1124                                 if(G.sipo->showkey==0) totipo_edit++;
1125                                 
1126                                 if(ei->icu) {
1127                                         if(ei->icu->bezt) {
1128                                                 bezt= ei->icu->bezt;
1129                                                 b= ei->icu->totvert;
1130                                                 while(b--) {
1131                                                         if(ei->icu->ipo==IPO_BEZ) {
1132                                                                 if(bezt->f1 & 1) totipo_vertsel++;
1133                                                                 if(bezt->f3 & 1) totipo_vertsel++;
1134                                                                 totipo_vert+= 2;
1135                                                         }
1136                                                         if(bezt->f2 & 1) totipo_vertsel++;
1137                                                         
1138                                                         totipo_vert++;
1139                                                         bezt++;
1140                                                 }
1141                                         }
1142                                 }
1143                         }
1144                 }
1145                 ei++;
1146         }
1147         
1148         if(G.sipo->showkey) {
1149                 ik= G.sipo->ipokey.first;
1150                 while(ik) {
1151                         totipo_key++;
1152                         if(ik->flag & 1) totipo_keysel++;
1153                         ik= ik->next;
1154                 }
1155         }
1156 }
1157
1158 /* synchronize editipo flag with icu flag and ipokey flags */
1159 void update_editipo_flags(void)
1160 {
1161         EditIpo *ei;
1162         IpoKey *ik;
1163         int a;
1164         
1165         ei= G.sipo->editipo;
1166         if(ei) {
1167                 for(a=0; a<G.sipo->totipo; a++, ei++) {
1168                         if(ei->icu) ei->icu->flag= ei->flag;
1169                 }
1170         }
1171         if(G.sipo->showkey) {
1172                 ik= G.sipo->ipokey.first;
1173                 while(ik) {
1174                         for(a=0; a<G.sipo->totipo; a++) {
1175                                 if(ik->data[a]) {
1176                                         if(ik->flag & 1) {
1177                                                 ik->data[a]->f1 |= 1;
1178                                                 ik->data[a]->f2 |= 1;
1179                                                 ik->data[a]->f3 |= 1;
1180                                         }
1181                                         else {
1182                                                 ik->data[a]->f1 &= ~1;
1183                                                 ik->data[a]->f2 &= ~1;
1184                                                 ik->data[a]->f3 &= ~1;
1185                                         }
1186                                 }
1187                         }
1188                         ik= ik->next;
1189                 }
1190         }
1191 }
1192
1193 /* sort of enter/leave editmode for curves */
1194 void set_editflag_editipo(void)
1195 {
1196         EditIpo *ei;
1197         int a; /*  , tot= 0, ok= 0; */
1198         
1199         /* after showkey immediately go to editing of selected points */
1200         if(G.sipo->showkey) {
1201                 G.sipo->showkey= 0;
1202                 if(G.sipo->ipo) G.sipo->ipo->showkey= 0;
1203                 ei= G.sipo->editipo;
1204                 for(a=0; a<G.sipo->totipo; a++, ei++) ei->flag |= IPO_SELECT;
1205                 scrarea_queue_headredraw(curarea);
1206                 allqueue(REDRAWVIEW3D, 0);
1207         }
1208         
1209         get_status_editipo();
1210         
1211         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1212         
1213         ei= G.sipo->editipo;
1214         for(a=0; a<G.sipo->totipo; a++, ei++) {         
1215                 if(ei->icu) {
1216                         if(ei->flag & IPO_VISIBLE) {
1217                                 
1218                                 if(totipo_edit==0 && (ei->flag & IPO_SELECT)) {
1219                                         ei->flag |= IPO_EDIT;
1220                                         ei->icu->flag= ei->flag;
1221                                 }
1222                                 else if(totipo_edit && (ei->flag & IPO_EDIT)) {
1223                                         ei->flag -= IPO_EDIT;
1224                                         ei->icu->flag= ei->flag;
1225                                 }
1226                                 else if(totipo_vis==1) {
1227                                         if(ei->flag & IPO_EDIT) ei->flag -= IPO_EDIT;
1228                                         else ei->flag |= IPO_EDIT;
1229                                         ei->icu->flag= ei->flag;
1230                                 }
1231                         }
1232                 }
1233         }
1234         scrarea_queue_headredraw(curarea);
1235         scrarea_queue_winredraw(curarea);
1236 }
1237
1238 static short findnearest_ipovert(IpoCurve **icu, BezTriple **bezt)
1239 {
1240         /* selected verts get a disadvantage */
1241         /* in icu and (bezt or bp) the nearest is written */
1242         /* return 0 1 2: handlepunt */
1243         EditIpo *ei;
1244         BezTriple *bezt1;
1245         int dist= 100, temp, a, b;
1246         short mval[2], hpoint=0, sco[3][2];
1247
1248         *icu= 0;
1249         *bezt= 0;
1250
1251         getmouseco_areawin(mval);
1252
1253         ei= G.sipo->editipo;
1254         for(a=0; a<G.sipo->totipo; a++, ei++) {
1255                 if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu)) {
1256                         
1257                         if(ei->icu->bezt) {
1258                                 bezt1= ei->icu->bezt;
1259                                 b= ei->icu->totvert;
1260                                 while(b--) {
1261
1262                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[0], sco[0]);
1263                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[1], sco[1]);
1264                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[2], sco[2]);
1265                                                                                 
1266                                         if(ei->disptype==IPO_DISPBITS) {
1267                                                 temp= abs(mval[0]- sco[1][0]);
1268                                         }
1269                                         else temp= abs(mval[0]- sco[1][0])+ abs(mval[1]- sco[1][1]);
1270
1271                                         if( bezt1->f2 & 1) temp+=5;
1272                                         if(temp<dist) { 
1273                                                 hpoint= 1; 
1274                                                 *bezt= bezt1; 
1275                                                 dist= temp; 
1276                                                 *icu= ei->icu; 
1277                                         }
1278                                         
1279                                         if(ei->disptype!=IPO_DISPBITS && ei->icu->ipo==IPO_BEZ) {
1280                                                 /* middle points get an advantage */
1281                                                 temp= -3+abs(mval[0]- sco[0][0])+ abs(mval[1]- sco[0][1]);
1282                                                 if( bezt1->f1 & 1) temp+=5;
1283                                                 if(temp<dist) { 
1284                                                         hpoint= 0; 
1285                                                         *bezt= bezt1; 
1286                                                         dist= temp; 
1287                                                         *icu= ei->icu; 
1288                                                 }
1289                 
1290                                                 temp= abs(mval[0]- sco[2][0])+ abs(mval[1]- sco[2][1]);
1291                                                 if( bezt1->f3 & 1) temp+=5;
1292                                                 if(temp<dist) { 
1293                                                         hpoint= 2; 
1294                                                         *bezt=bezt1; 
1295                                                         dist= temp; 
1296                                                         *icu= ei->icu; 
1297                                                 }
1298                                         }
1299                                         bezt1++;
1300                                 }
1301                         }
1302                 }
1303         }
1304
1305         return hpoint;
1306 }
1307
1308 void mouse_select_ipo(void)
1309 {
1310         Object *ob;
1311         KeyBlock *actkb=NULL;
1312         EditIpo *ei, *actei= 0;
1313         IpoCurve *icu;
1314         IpoKey *ik, *actik;
1315         BezTriple *bezt;
1316         float x, y, dist, mindist;
1317         int a, oldflag = 0, hand, ok;
1318         short mval[2], xo, yo;
1319         
1320         if(G.sipo->editipo==0) return;
1321         
1322         get_status_editipo();
1323         
1324         if(G.sipo->showkey) {
1325                 getmouseco_areawin(mval);
1326                 
1327                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1328                 actik= 0;
1329                 mindist= 1000.0;
1330                 ik= G.sipo->ipokey.first;
1331                 while(ik) {
1332                         dist= (float)(fabs(ik->val-x));
1333                         if(ik->flag & 1) dist+= 1.0;
1334                         if(dist < mindist) {
1335                                 actik= ik;
1336                                 mindist= dist;
1337                         }
1338                         ik= ik->next;
1339                 }
1340                 if(actik) {
1341                         oldflag= actik->flag;
1342                         
1343                         if(G.qual & LR_SHIFTKEY);
1344                         else deselectall_editipo();
1345                         
1346                         if(G.qual & LR_SHIFTKEY) {
1347                                 if(oldflag & 1) actik->flag &= ~1;
1348                                 else actik->flag |= 1;
1349                         }
1350                         else {
1351                                 actik->flag |= 1;
1352                         }
1353                 }
1354         }
1355         else if(totipo_edit) {
1356                 
1357                 hand= findnearest_ipovert(&icu, &bezt);
1358                 
1359                 if(G.qual & LR_SHIFTKEY) {
1360                         if(bezt) {
1361                                 if(hand==1) {
1362                                         if(BEZSELECTED(bezt)) {
1363                                                 bezt->f1= bezt->f2= bezt->f3= 0;
1364                                         }
1365                                         else {
1366                                                 bezt->f1= bezt->f2= bezt->f3= 1;
1367                                         }
1368                                 }
1369                                 else if(hand==0) {
1370                                         if(bezt->f1 & 1) bezt->f1= 0;
1371                                         else bezt->f1= 1;
1372                                 }
1373                                 else {
1374                                         if(bezt->f3 & 1) bezt->f3= 0;
1375                                         else bezt->f3= 1;
1376                                 }
1377                         }                               
1378                 }
1379                 else {
1380                         deselectall_editipo();
1381                         
1382                         if(bezt) {
1383                                 if(hand==1) {
1384                                         bezt->f1|= 1; bezt->f2|= 1; bezt->f3|= 1;
1385                                 }
1386                                 else if(hand==0) bezt->f1|= 1;
1387                                 else bezt->f3|= 1;
1388                         }
1389                 }
1390         }
1391         else {
1392                 
1393                 /* vertex keys ? */
1394                 if(G.sipo->blocktype==ID_KE && G.sipo->from) {
1395                         Key *key;
1396                         KeyBlock *kb, *curkb;
1397                         int i, index= 1;
1398                         
1399                         ob= (Object *)G.sipo->from;
1400                         key= ob_get_key(ob);
1401                         curkb= BLI_findlink(&key->block, ob->shapenr-1);
1402                         
1403                         ei= G.sipo->editipo;
1404                         if(key->type==KEY_NORMAL || (ei->flag & IPO_VISIBLE)) {
1405                                 getmouseco_areawin(mval);
1406                                 
1407                                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1408                                 /* how much is 20 pixels? */
1409                                 mindist= (float)(20.0*(G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)curarea->winy);
1410                                 
1411                                 for(i=1, kb= key->block.first; kb; kb= kb->next, i++) {
1412                                         dist= (float)(fabs(kb->pos-y));
1413                                         if(kb==curkb) dist+= (float)0.01;
1414                                         if(dist < mindist) {
1415                                                 actkb= kb;
1416                                                 mindist= dist;
1417                                                 index= i;
1418                                         }
1419                                 }
1420                                 if(actkb) {
1421                                         ok= TRUE;
1422                                         if(G.obedit && actkb!=curkb) {
1423                                                 ok= okee("Copy key after leaving Edit Mode");
1424                                         }
1425                                         if(ok) {
1426                                                 /* also does all keypos */
1427                                                 deselectall_editipo();
1428                                                 set_active_key(index);
1429                                                 set_active_editipo(ei+index-1);
1430                                         }
1431                                 }
1432                         }
1433                 }
1434                 
1435                 /* select curve */
1436                 if(actkb==NULL) {
1437                         if(totipo_vis==1) {
1438                                 ei= G.sipo->editipo;
1439                                 for(a=0; a<G.sipo->totipo; a++, ei++) {
1440                                         if(ei->icu) {
1441                                                 if(ei->flag & IPO_VISIBLE) actei= ei;
1442                                         }
1443                                 }
1444                         }
1445                         else if(totipo_vis>1) {
1446                                 actei= select_proj_ipo(0, 0);
1447                         }
1448                         
1449                         if(actei) oldflag= actei->flag;
1450                         
1451                         if(G.qual & LR_SHIFTKEY);
1452                         else deselectall_editipo();
1453                         
1454                         if(actei) {
1455                                 if(G.qual & LR_SHIFTKEY) {
1456                                         if(oldflag & IPO_SELECT) actei->flag &= ~IPO_SELECT;
1457                                         else actei->flag |= IPO_SELECT;
1458                                 }
1459                                 else {
1460                                         actei->flag |= IPO_SELECT;
1461                                 }
1462                                 set_active_editipo(actei);
1463                         }
1464                 }
1465         }
1466         
1467         update_editipo_flags();
1468         
1469         force_draw(0);
1470         BIF_undo_push("Select Ipo");
1471         
1472         if(G.sipo->showkey && G.sipo->blocktype==ID_OB) {
1473                 ob= OBACT;
1474                 if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
1475         }
1476         
1477         getmouseco_areawin(mval);
1478         xo= mval[0]; 
1479         yo= mval[1];
1480         
1481         while(get_mbut()&R_MOUSE) {             
1482                 getmouseco_areawin(mval);
1483                 if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
1484                         
1485                         if(actkb) move_keys(OBACT);
1486                         else transform_ipo('g');
1487                         
1488                         return;
1489                 }
1490                 BIF_wait_for_statechange();
1491         }
1492 }
1493
1494
1495 /* *********************************** */
1496
1497 /* handling of right-hand channel/curve buttons in ipo window */
1498 void do_ipowin_buts(short event)
1499 {
1500         EditIpo *ei = NULL;
1501         int a;
1502
1503         /* without shift, all other channels are made invisible */
1504         if((G.qual & LR_SHIFTKEY)==0) {
1505                 if(event>G.sipo->totipo) return;
1506                 ei = G.sipo->editipo;
1507                 for(a=0; a<G.sipo->totipo; a++) {
1508                         if(a!=event) ei->flag &= ~IPO_VISIBLE;
1509                         else ei->flag |= IPO_VISIBLE;
1510                         ei++;
1511                 }
1512         }
1513         
1514         /* set active */
1515         if(event>=0 && event<G.sipo->totipo) {
1516                 ei= G.sipo->editipo;    // void pointer...
1517                 set_active_editipo(ei+event);
1518                 set_active_key(event+1);        // only if there's a key, of course
1519         }
1520         scrarea_queue_winredraw(curarea);
1521         
1522         update_editipo_flags();
1523         get_status_editipo();
1524
1525         if(G.sipo->showkey) {
1526                 make_ipokey();
1527                 if(G.sipo->blocktype==ID_OB) allqueue(REDRAWVIEW3D, 0);
1528         }
1529
1530 }
1531
1532 /* the fake buttons to the left of channel names, for select/deselect curves */
1533 void do_ipo_selectbuttons(void)
1534 {
1535         EditIpo *ei, *ei1;
1536         int a, nr;
1537         short mval[2];
1538         
1539         if(G.sipo->showkey) return;
1540         
1541         /* do not allow editipo here: convert editipos to selected */
1542         get_status_editipo();
1543         if(totipo_edit) {
1544                 set_editflag_editipo();
1545         }
1546         
1547         /* which */
1548         getmouseco_areawin(mval);
1549
1550         nr= -(mval[1]-curarea->winy+30-G.sipo->butofs-IPOBUTY)/IPOBUTY;
1551         if(nr>=0 && nr<G.sipo->totipo) {
1552                 ei= G.sipo->editipo;
1553                 ei+= nr;
1554                 
1555                 set_active_editipo(ei);
1556                 set_active_key(nr+1);
1557
1558                 if(ei->icu) {
1559                         if((ei->flag & IPO_VISIBLE)==0) {
1560                                 ei->flag |= IPO_VISIBLE|IPO_SELECT;
1561                         }
1562         
1563                         if((G.qual & LR_SHIFTKEY)==0) {
1564                                 ei1= G.sipo->editipo;
1565                                 for(a=0; a<G.sipo->totipo; a++) {
1566                                         ei1->flag &= ~IPO_SELECT;
1567                                         ei1++;
1568                                 }
1569                         }
1570
1571                         if(ei->flag & IPO_SELECT) {
1572                                 ei->flag &= ~IPO_SELECT;
1573                         }
1574                         else {
1575                                 ei->flag |= IPO_SELECT;
1576                         }
1577                         
1578                         update_editipo_flags();
1579                         scrarea_queue_winredraw(curarea);
1580                 }
1581         }
1582         BIF_undo_push("Select Ipo curve");
1583 }
1584
1585 /* ********************************* Inserting keys ********************************************* */
1586
1587 /* depending type, it returns ipo, if neded it creates one */
1588 /* returns either action ipo or "real" ipo */
1589 /* arguments define full context;
1590    - *from has to be set always, to Object in case of Actions
1591    - blocktype defines available channels of Ipo struct (blocktype ID_OB can be in action too)
1592    - if actname, use this to locate action, and optional constname to find the channel 
1593 */
1594
1595 /* note; check header_ipo.c, spaceipo_assign_ipo() too */
1596 Ipo *verify_ipo(ID *from, short blocktype, char *actname, char *constname)
1597 {
1598
1599         if(from==NULL || from->lib) return NULL;
1600         
1601         /* first check action ipos */
1602         if(actname && actname[0]) {
1603                 Object *ob= (Object *)from;
1604                 bActionChannel *achan;
1605                 
1606                 if(GS(from->name)!=ID_OB) {
1607                         printf("called ipo system for action with wrong base pointer\n");
1608                         return NULL;
1609                 }
1610                 
1611                 if(ob->action==NULL)
1612                         ob->action= add_empty_action(blocktype);
1613                 
1614                 achan= verify_action_channel(ob->action, actname);
1615                 
1616                 if(achan) {
1617                         /* constraint exception */
1618                         if(blocktype==ID_CO) {
1619                                 bConstraintChannel *conchan= verify_constraint_channel(&achan->constraintChannels, constname);
1620                                 if(conchan->ipo==NULL) {
1621                                         conchan->ipo= add_ipo("CoIpo", ID_CO);  
1622                                 }
1623                                 return conchan->ipo;
1624                         }
1625                         else {
1626                                 if(achan->ipo==NULL) {
1627                                         achan->ipo= add_ipo("ActIpo", blocktype);
1628                                 }
1629                                 
1630                                 return achan->ipo;
1631                         }
1632                 }
1633         }
1634         else {
1635                 
1636                 switch(GS(from->name)) {
1637                 case ID_OB:
1638                         {
1639                                 Object *ob= (Object *)from;
1640                                 /* constraint exception */
1641                                 if(blocktype==ID_CO) {
1642                                         bConstraintChannel *conchan= verify_constraint_channel(&ob->constraintChannels, constname);
1643                                         if(conchan->ipo==NULL) {
1644                                                 conchan->ipo= add_ipo("CoIpo", ID_CO);  
1645                                         }
1646                                         return conchan->ipo;
1647                                 }
1648                                 else if(blocktype==ID_OB) {
1649                                         if(ob->ipo==NULL) {
1650                                                 ob->ipo= add_ipo("ObIpo", ID_OB);
1651                                         }
1652                                         return ob->ipo;
1653                                 }
1654                                 else if(blocktype==ID_KE) {
1655                                         Key *key= ob_get_key((Object *)from);
1656                                         
1657                                         if(key) {
1658                                                 if(key->ipo==NULL) {
1659                                                         key->ipo= add_ipo("KeyIpo", ID_KE);
1660                                                 }
1661                                                 return key->ipo;
1662                                         }
1663                                         return NULL;
1664                                 }
1665                         }
1666                         break;
1667                 case ID_MA:
1668                         {
1669                                 Material *ma= (Material *)from;
1670
1671                                 if(ma->ipo==NULL) {
1672                                         ma->ipo= add_ipo("MatIpo", ID_MA);
1673                                 }
1674                                 return ma->ipo;
1675                         }
1676                         break;
1677                 case ID_TE:
1678                         {
1679                                 Tex *tex= (Tex *)from;
1680
1681                                 if(tex->ipo==NULL) {
1682                                         tex->ipo= add_ipo("TexIpo", ID_TE);
1683                                 }
1684                                 return tex->ipo;
1685                         }
1686                         break;
1687                 case ID_SEQ:
1688                         {
1689                                 Sequence *seq= (Sequence *)from;        /* note, sequence is mimicing Id */
1690
1691                                 if((seq->type & SEQ_EFFECT)||(seq->type == SEQ_SOUND)) {
1692                                         if(seq->ipo==NULL) {
1693                                                 seq->ipo= add_ipo("SeqIpo", ID_SEQ);
1694                                         }
1695                                         return seq->ipo;
1696                                 }
1697                         }
1698                         break;
1699                 case ID_CU:
1700                         {
1701                                 Curve *cu= (Curve *)from;
1702                                 
1703                                 if(cu->ipo==NULL) {
1704                                         cu->ipo= add_ipo("CuIpo", ID_CU);
1705                                 }
1706                                 return cu->ipo;
1707                         }
1708                         break;
1709                 case ID_WO:
1710                         {
1711                                 World *wo= (World *)from;
1712
1713                                 if(wo->ipo==NULL) {
1714                                         wo->ipo= add_ipo("WoIpo", ID_WO);
1715                                 }
1716                                 return wo->ipo;
1717                         }
1718                         break;
1719                 case ID_LA:
1720                         {
1721                                 Lamp *la= (Lamp *)from;
1722                                 
1723                                 if(la->ipo==NULL) {
1724                                         la->ipo= add_ipo("LaIpo", ID_LA);
1725                                 }
1726                                 return la->ipo;
1727                         }
1728                         break;
1729                 case ID_CA:
1730                         {
1731                                 Camera *ca= (Camera *)from;
1732
1733                                 if(ca->ipo==NULL) {
1734                                         ca->ipo= add_ipo("CaIpo", ID_CA);
1735                                 }
1736                                 return ca->ipo;
1737                         }
1738                         break;
1739                 case ID_SO:
1740                         {
1741                                 bSound *snd= (bSound *)from;
1742
1743                                 if(snd->ipo==NULL) {
1744                                         snd->ipo= add_ipo("SndIpo", ID_SO);
1745                                 }
1746                                 return snd->ipo;
1747                         }
1748                 }
1749         }
1750         
1751         return NULL;    
1752 }
1753
1754 /* returns and creates */
1755 IpoCurve *verify_ipocurve(ID *from, short blocktype, char *actname, char *constname, int adrcode)
1756 {
1757         Ipo *ipo;
1758         IpoCurve *icu= NULL;
1759         
1760         /* return 0 if lib */
1761         /* creates ipo too */
1762         ipo= verify_ipo(from, blocktype, actname, constname);
1763         
1764         if(ipo && ipo->id.lib==NULL) {
1765                 
1766                 for(icu= ipo->curve.first; icu; icu= icu->next) {
1767                         if(icu->adrcode==adrcode) break;
1768                 }
1769                 if(icu==NULL) {
1770                         icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
1771
1772                         icu->flag |= IPO_VISIBLE|IPO_AUTO_HORIZ;
1773                         icu->blocktype= blocktype;
1774                         icu->adrcode= adrcode;
1775                         
1776                         set_icu_vars(icu);
1777                         
1778                         BLI_addtail( &(ipo->curve), icu);
1779                 }
1780         }
1781
1782         return icu;
1783 }
1784
1785 void insert_vert_ipo(IpoCurve *icu, float x, float y)
1786 {
1787         BezTriple *bezt, beztr, *newbezt;
1788         int a = 0, h1, h2;
1789         
1790         memset(&beztr, 0, sizeof(BezTriple));
1791         beztr.vec[0][0]= x; // set all three points, for nicer start position
1792         beztr.vec[0][1]= y;
1793         beztr.vec[1][0]= x;
1794         beztr.vec[1][1]= y;
1795         beztr.vec[2][0]= x;
1796         beztr.vec[2][1]= y;
1797         beztr.hide= IPO_BEZ;
1798         beztr.f1= beztr.f2= beztr.f3= SELECT;
1799         beztr.h1= beztr.h2= HD_AUTO;
1800                 
1801         bezt= icu->bezt;
1802                 
1803         if(bezt==NULL) {
1804                 icu->bezt= MEM_callocN( sizeof(BezTriple), "beztriple");
1805                 *(icu->bezt)= beztr;
1806                 icu->totvert= 1;
1807         }
1808         else {
1809                 /* all vertices deselect */
1810                 for(a=0; a<icu->totvert; a++, bezt++) {
1811                         bezt->f1= bezt->f2= bezt->f3= 0;
1812                 }
1813         
1814                 bezt= icu->bezt;
1815                 for(a=0; a<=icu->totvert; a++, bezt++) {
1816                         
1817                         /* no double points */
1818                         if(a<icu->totvert && (bezt->vec[1][0]>x-IPOTHRESH && bezt->vec[1][0]<x+IPOTHRESH)) {
1819                                 *(bezt)= beztr;
1820                                 break;
1821                         }
1822                         if(a==icu->totvert || bezt->vec[1][0] > x) {
1823                                 newbezt= MEM_callocN( (icu->totvert+1)*sizeof(BezTriple), "beztriple");
1824                                 
1825                                 if(a>0) memcpy(newbezt, icu->bezt, a*sizeof(BezTriple));
1826                                 
1827                                 bezt= newbezt+a;
1828                                 *(bezt)= beztr;
1829                                 
1830                                 if(a<icu->totvert) memcpy(newbezt+a+1, icu->bezt+a, (icu->totvert-a)*sizeof(BezTriple));
1831                                 
1832                                 MEM_freeN(icu->bezt);
1833                                 icu->bezt= newbezt;
1834                                 
1835                                 icu->totvert++;
1836                                 break;
1837                         }
1838                 }
1839         }
1840         
1841         
1842         calchandles_ipocurve(icu);
1843         
1844         /* set handletype */
1845         if(icu->totvert>2) {
1846                 h1= h2= HD_AUTO;
1847                 if(a>0) h1= (bezt-1)->h2;
1848                 if(a<icu->totvert-1) h2= (bezt+1)->h1;
1849                 bezt->h1= h1;
1850                 bezt->h2= h2;
1851
1852                 calchandles_ipocurve(icu);
1853         }
1854 }
1855
1856 void add_vert_ipo(void)
1857 {
1858         EditIpo *ei;
1859         float x, y;
1860         int val;
1861         short mval[2];
1862
1863         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1864         if(G.sipo->showkey) {
1865                 G.sipo->showkey= 0;
1866                 free_ipokey(&G.sipo->ipokey);
1867         }
1868         
1869         getmouseco_areawin(mval);
1870         
1871         if(mval[0]>G.v2d->mask.xmax) return;
1872         
1873         ei= get_active_editipo();
1874         if(ei==NULL) {
1875                 error("No active Ipo curve");
1876                 return;
1877         }
1878         ei->flag |= IPO_VISIBLE;        /* can happen it is active but not visible */
1879         
1880         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1881         
1882         if(ei->icu==NULL) {
1883                 if(G.sipo->from) {
1884                         ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei->adrcode);
1885                         ei->flag |= ei->icu->flag & IPO_AUTO_HORIZ;     /* new curve could have been added, weak... */
1886                 }
1887         }
1888         if(ei->icu==NULL) return;
1889
1890         if(ei->disptype==IPO_DISPBITS) {
1891                 ei->icu->vartype= IPO_BITS;
1892                 val= (int)floor(y-0.5);
1893                 if(val<0) val= 0;
1894                 y= (float)(1 << val);
1895         }
1896         
1897         insert_vert_ipo(ei->icu, x, y);
1898
1899         /* to be sure: if icu was 0, or only 1 curve visible */
1900         ei->flag |= IPO_SELECT;
1901         ei->icu->flag= ei->flag;
1902         
1903         editipo_changed(G.sipo, 1);
1904         BIF_undo_push("Add Ipo vertex");
1905 }
1906
1907 static void *get_context_ipo_poin(ID *id, int blocktype, char *actname, IpoCurve *icu, int *vartype)
1908 {
1909         if(blocktype==ID_PO) {
1910                 if(GS(id->name)==ID_OB) {
1911                         Object *ob= (Object *)id;
1912                         bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
1913                         
1914                         *vartype= IPO_FLOAT;
1915                         return get_pchan_ipo_poin(pchan, icu->adrcode);
1916                 }
1917                 return NULL;
1918         }
1919         else
1920                 return get_ipo_poin(id, icu, vartype);
1921
1922 }
1923
1924 void insertkey(ID *id, int blocktype, char *actname, char *constname, int adrcode)
1925 {
1926         IpoCurve *icu;
1927         Object *ob;
1928         void *poin= NULL;
1929         float curval, cfra;
1930         int vartype;
1931         
1932         icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
1933         
1934         if(icu) {
1935                 
1936                 poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
1937                 
1938                 if(poin) {
1939                         curval= read_ipo_poin(poin, vartype);
1940                         
1941                         cfra= frame_to_float(CFRA);
1942                         
1943                         /* if action is mapped in NLA, it returns a correction */
1944                         if(actname && actname[0] && GS(id->name)==ID_OB)
1945                                 cfra= get_action_frame((Object *)id, cfra);
1946                         
1947                         if( GS(id->name)==ID_OB ) {
1948                                 ob= (Object *)id;
1949                                 if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
1950                                         /* actually frametofloat calc again! */
1951                                         cfra-= ob->sf*G.scene->r.framelen;
1952                                 }
1953                         }
1954                         
1955                         insert_vert_ipo(icu, cfra, curval);
1956                 }
1957         }
1958 }
1959
1960 void insertkey_editipo(void)
1961 {
1962         EditIpo *ei;
1963         IpoKey *ik;
1964         ID *id;
1965         float *fp, cfra, *insertvals;
1966         int a, nr, ok, tot;
1967         short event;
1968         
1969         ei= get_active_editipo();
1970         if(ei && ei->icu && ei->icu->driver) 
1971                 event= pupmenu("Insert Curve %t|Default one-to-one mapping %x3");
1972         else if(G.sipo->showkey)
1973                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1|Selected Keys %x2");
1974         else 
1975                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1");
1976         
1977         if(event<1) return;
1978         
1979         if(event==3) {
1980                 IpoDriver *driver= ei->icu->driver;
1981                 
1982                 if(ei->icu->bezt) MEM_freeN(ei->icu->bezt);
1983                 ei->icu->totvert= 0;
1984                 ei->icu->bezt= NULL;
1985                 
1986                 insert_vert_ipo(ei->icu, 0.0f, 0.0f);
1987                 
1988                 if(ELEM3(driver->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
1989                         if(ei->disptype==IPO_DISPDEGR)
1990                                 insert_vert_ipo(ei->icu, 18.0f, 18.0f);
1991                         else
1992                                 insert_vert_ipo(ei->icu, 18.0f, 1.0f);
1993                 }
1994                 else
1995                         insert_vert_ipo(ei->icu, 1.0f, 1.0f);
1996                 
1997                 ei->flag |= IPO_SELECT|IPO_VISIBLE;
1998                 ei->icu->flag= ei->flag;
1999                 ei->icu->extrap= IPO_DIR;
2000
2001                 do_ipo_buttons(B_IPOHOME);
2002         }
2003         else {
2004                 ei= G.sipo->editipo;
2005                 for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
2006                         if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
2007                         
2008                                 ok= 0;
2009                                 if(G.sipo->showkey) ok= 1;
2010                                 else if(ei->flag & IPO_SELECT) ok= 1;
2011
2012                                 if(ok) {
2013                                         /* count amount */
2014                                         if(event==1) tot= 1;
2015                                         else {
2016                                                 ik= G.sipo->ipokey.first;
2017                                                 tot= 0;
2018                                                 while(ik) {
2019                                                         if(ik->flag & 1) tot++;
2020                                                         ik= ik->next;
2021                                                 }
2022                                         }
2023                                         if(tot) {
2024                                         
2025                                                 /* correction for ob timeoffs */
2026                                                 cfra= frame_to_float(CFRA);
2027                                                 id= G.sipo->from;       
2028                                                 if(id && GS(id->name)==ID_OB ) {
2029                                                         Object *ob= (Object *)id;
2030                                                         if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
2031                                                                 cfra-= ob->sf*G.scene->r.framelen;
2032                                                         }
2033                                                 }
2034                                                 else if(id && GS(id->name)==ID_SEQ) {
2035                                                         extern Sequence *last_seq;      /* editsequence.c */
2036                                                         
2037                                                         if(last_seq) {
2038                                                                 cfra= (float)(100.0*(cfra-last_seq->startdisp)/((float)(last_seq->enddisp-last_seq->startdisp)));
2039                                                         }
2040                                                 }
2041                                 
2042                                                 insertvals= MEM_mallocN(sizeof(float)*2*tot, "insertkey_editipo");
2043                                                 /* make sure icu->curval is correct */
2044                                                 calc_ipo(G.sipo->ipo, cfra);
2045                                                 
2046                                                 if(event==1) {
2047                                                         insertvals[0]= cfra;
2048                                                         
2049                                                         insertvals[1]= ei->icu->curval;
2050                                                 }
2051                                                 else {
2052                                                         fp= insertvals;
2053                                                         ik= G.sipo->ipokey.first;
2054                                                         while(ik) {
2055                                                                 if(ik->flag & 1) {
2056                                                                         calc_ipo(G.sipo->ipo, ik->val);
2057
2058                                                                         fp[0]= ik->val;
2059                                                                         fp[1]= ei->icu->curval;
2060                                                                         fp+= 2;
2061                                                                 }
2062                                                                 ik= ik->next;
2063                                                         }
2064                                                 }
2065                                                 fp= insertvals;
2066                                                 for(a=0; a<tot; a++, fp+=2) {
2067                                                         insert_vert_ipo(ei->icu, fp[0], fp[1]);
2068                                                 }
2069                                                 
2070                                                 MEM_freeN(insertvals);
2071                                                 calc_ipo(G.sipo->ipo, (float)CFRA);
2072                                         }
2073                                 }
2074                         }
2075                 }
2076         }
2077         BIF_undo_push("Insert Key Ipo");
2078         allqueue (REDRAWACTION, 0);
2079         allqueue(REDRAWNLA, 0);
2080         allqueue(REDRAWIPO, 0);
2081         allspace(REMAKEIPO, 0);
2082 }
2083
2084
2085 void common_insertkey(void)
2086 {
2087         Base *base;
2088         Object *ob;
2089         Material *ma;
2090         ID *id;
2091         IpoCurve *icu;
2092         World *wo;
2093         Lamp *la;
2094         int tlay, map, event;
2095         char menustr[256];
2096         
2097         if(curarea->spacetype==SPACE_IPO) {
2098                 insertkey_editipo();
2099         }
2100         else if(curarea->spacetype==SPACE_BUTS) {
2101                 if(G.buts->mainb==CONTEXT_SHADING) {
2102                         int tab= G.buts->tab[CONTEXT_SHADING];
2103                         
2104                         if(tab==TAB_SHADING_MAT) {
2105                                 id= G.buts->lockpoin;
2106                                 ma= G.buts->lockpoin;
2107                                 if(id) {
2108                                         event= pupmenu("Insert Key %t|RGB%x0|Alpha%x1|Halo Size%x2|Mode %x3|All Color%x10|All Mirror%x14|Ofs%x12|Size%x13|All Mapping%x11");
2109                                         if(event== -1) return;
2110                                         
2111                                         map= texchannel_to_adrcode(ma->texact);
2112                                         
2113                                         if(event==0 || event==10) {
2114                                                 insertkey(id, ID_MA, NULL, NULL, MA_COL_R);
2115                                                 insertkey(id, ID_MA, NULL, NULL, MA_COL_G);
2116                                                 insertkey(id, ID_MA, NULL, NULL, MA_COL_B);
2117                                         }
2118                                         if(event==1 || event==10) {
2119                                                 insertkey(id, ID_MA, NULL, NULL, MA_ALPHA);
2120                                         }
2121                                         if(event==2 || event==10) {
2122                                                 insertkey(id, ID_MA, NULL, NULL, MA_HASIZE);
2123                                         }
2124                                         if(event==3 || event==10) {
2125                                                 insertkey(id, ID_MA, NULL, NULL, MA_MODE);
2126                                         }
2127                                         if(event==10) {
2128                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC_R);
2129                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC_G);
2130                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC_B);
2131                                                 insertkey(id, ID_MA, NULL, NULL, MA_REF);
2132                                                 insertkey(id, ID_MA, NULL, NULL, MA_EMIT);
2133                                                 insertkey(id, ID_MA, NULL, NULL, MA_AMB);
2134                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC);
2135                                                 insertkey(id, ID_MA, NULL, NULL, MA_HARD);
2136                                                 insertkey(id, ID_MA, NULL, NULL, MA_MODE);
2137                                                 insertkey(id, ID_MA, NULL, NULL, MA_TRANSLU);
2138                                                 insertkey(id, ID_MA, NULL, NULL, MA_ADD);
2139                                         }
2140                                         if(event==14) {
2141                                                 insertkey(id, ID_MA, NULL, NULL, MA_RAYM);
2142                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESMIR);
2143                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESMIRI);
2144                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESTRA);
2145                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESTRAI);
2146                                         }
2147                                         if(event==12 || event==11) {
2148                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_X);
2149                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_Y);
2150                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_Z);
2151                                         }
2152                                         if(event==13 || event==11) {
2153                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_X);
2154                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_Y);
2155                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_Z);
2156                                         }
2157                                         if(event==11) {
2158                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_R);
2159                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_G);
2160                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_B);
2161                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_DVAR);
2162                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_COLF);
2163                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_NORF);
2164                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_VARF);
2165                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_DISP);
2166                                         }
2167                                 }
2168                         }
2169                         else if(tab==TAB_SHADING_WORLD) {
2170                                 id= G.buts->lockpoin;
2171                                 wo= G.buts->lockpoin;
2172                                 if(id) {
2173                                         event= pupmenu("Insert Key %t|Zenith RGB%x0|Horizon RGB%x1|Mist%x2|Stars %x3|Offset%x12|Size%x13");
2174                                         if(event== -1) return;
2175                                         
2176                                         map= texchannel_to_adrcode(wo->texact);
2177                                         
2178                                         if(event==0) {
2179                                                 insertkey(id, ID_WO, NULL, NULL, WO_ZEN_R);
2180                                                 insertkey(id, ID_WO, NULL, NULL, WO_ZEN_G);
2181                                                 insertkey(id, ID_WO, NULL, NULL, WO_ZEN_B);
2182                                         }
2183                                         if(event==1) {
2184                                                 insertkey(id, ID_WO, NULL, NULL, WO_HOR_R);
2185                                                 insertkey(id, ID_WO, NULL, NULL, WO_HOR_G);
2186                                                 insertkey(id, ID_WO, NULL, NULL, WO_HOR_B);
2187                                         }
2188                                         if(event==2) {
2189                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISI);
2190                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISTDI);
2191                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISTSTA);
2192                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISTHI);
2193                                         }
2194                                         if(event==3) {
2195                                                 insertkey(id, ID_WO, NULL, NULL, WO_STAR_R);
2196                                                 insertkey(id, ID_WO, NULL, NULL, WO_STAR_G);
2197                                                 insertkey(id, ID_WO, NULL, NULL, WO_STAR_B);
2198                                                 insertkey(id, ID_WO, NULL, NULL, WO_STARDIST);
2199                                                 insertkey(id, ID_WO, NULL, NULL, WO_STARSIZE);
2200                                         }
2201                                         if(event==12) {
2202                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_X);
2203                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_Y);
2204                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_Z);
2205                                         }
2206                                         if(event==13) {
2207                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_X);
2208                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_Y);
2209                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_Z);
2210                                         }
2211                                 }
2212                         }
2213                         else if(tab==TAB_SHADING_LAMP) {
2214                                 id= G.buts->lockpoin;
2215                                 la= G.buts->lockpoin;
2216                                 if(id) {
2217                                         event= pupmenu("Insert Key %t|RGB%x0|Energy%x1|Spot Size%x2|Offset%x12|Size%x13");
2218                                         if(event== -1) return;
2219                                         
2220                                         map= texchannel_to_adrcode(la->texact);
2221                                         
2222                                         if(event==0) {
2223                                                 insertkey(id, ID_LA, NULL, NULL, LA_COL_R);
2224                                                 insertkey(id, ID_LA, NULL, NULL, LA_COL_G);
2225                                                 insertkey(id, ID_LA, NULL, NULL, LA_COL_B);
2226                                         }
2227                                         if(event==1) {
2228                                                 insertkey(id, ID_LA, NULL, NULL, LA_ENERGY);
2229                                         }
2230                                         if(event==2) {
2231                                                 insertkey(id, ID_LA, NULL, NULL, LA_SPOTSI);
2232                                         }
2233                                         if(event==12) {
2234                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_X);
2235                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_Y);
2236                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_Z);
2237                                         }
2238                                         if(event==13) {
2239                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_X);
2240                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_Y);
2241                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_Z);
2242                                         }
2243
2244                                 }
2245                         }
2246                 }
2247                 else if(G.buts->mainb==CONTEXT_OBJECT) {
2248                         ob= OBACT;
2249                         if(ob && ob->type==OB_MESH) {
2250                                 id= (ID *) (ob);
2251                                 if(id) {
2252                                         event= pupmenu("Insert Key %t|Surface Damping%x0|Random Damping%x1|Permeability%x2|Force Strength%x3|Force Falloff%x4");
2253                                         if(event== -1) return;
2254
2255                                         if(event==0) {
2256                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_SDAMP);
2257                                         }
2258                                         if(event==1) {
2259                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_RDAMP);
2260                                         }
2261                                         if(event==2) {
2262                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_PERM);
2263                                         }
2264                                         if(event==3) {
2265                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_FSTR);
2266                                         }
2267                                         if(event==4) {
2268                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_FFALL);
2269                                         }
2270
2271                                 }
2272                         }
2273                 }
2274                 else if(G.buts->mainb==CONTEXT_EDITING) {
2275                         ob= OBACT;
2276                         if(ob && ob->type==OB_CAMERA) {
2277                                 id= G.buts->lockpoin;
2278                                 if(id) {
2279                                         /* yafray: insert key extended with aperture and focal distance */
2280                                         if (G.scene->r.renderer==R_INTERN)
2281                                                 event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1");
2282                                         else
2283                                                 event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1|Aperture%x2|FocalDistance%x3");
2284                                         if(event== -1) return;
2285
2286                                         if(event==0) {
2287                                                 insertkey(id, ID_CA, NULL, NULL, CAM_LENS);
2288                                         }
2289                                         else if(event==1) {
2290                                                 insertkey(id, ID_CA, NULL, NULL, CAM_STA);
2291                                                 insertkey(id, ID_CA, NULL, NULL, CAM_END);
2292                                         }
2293                                         else if(event==2) {
2294                                                 insertkey(id, ID_CA, NULL, NULL, CAM_YF_APERT);
2295                                         }
2296                                         else if(event==3) {
2297                                                 insertkey(id, ID_CA, NULL, NULL, CAM_YF_FDIST);
2298                                         }
2299                                 }
2300                         }
2301                 }
2302                 else if(FALSE /* && G.buts->mainb==BUTS_SOUND */) {
2303                         if(G.ssound) {
2304                                 id= G.buts->lockpoin;
2305                                 if(id) {
2306                                         event= pupmenu("Insert Key %t|Volume%x0|Pitch%x1|Panning%x2|Attennuation%x3");
2307                                         if(event== -1) return;
2308
2309                                         if(event==0) {
2310                                                 insertkey(id, ID_SO, NULL, NULL, SND_VOLUME);
2311                                         }
2312                                         if(event==1) {
2313                                                 insertkey(id, ID_SO, NULL, NULL, SND_PITCH);
2314                                         }
2315                                         if(event==2) {
2316                                                 insertkey(id, ID_SO, NULL, NULL, SND_PANNING);
2317                                         }
2318                                         if(event==3) {
2319                                                 insertkey(id, ID_SO, NULL, NULL, SND_ATTEN);
2320                                         }
2321                                 }
2322                         }
2323                 }
2324                 
2325                 BIF_undo_push("Insert Key Buttons");
2326
2327                 allqueue(REDRAWACTION, 0);
2328                 allqueue(REDRAWNLA, 0);
2329                 allqueue(REDRAWIPO, 0);
2330                 allspace(REMAKEIPO, 0);
2331
2332         }
2333         else if(curarea->spacetype==SPACE_VIEW3D) {
2334                 ob= OBACT;
2335
2336                 if (ob && (ob->flag & OB_POSEMODE)) {
2337                         strcpy(menustr, "Insert Key%t|Loc%x0|Rot%x1|Size%x2|LocRot%x3|LocRotSize%x4|Avail%x9");
2338                 }
2339                 else {
2340                         base= FIRSTBASE;
2341                         while(base) {
2342                                 if TESTBASELIB(base) break;
2343                                 base= base->next;
2344                         }
2345                         if(base==NULL) return;
2346                 
2347                         strcpy(menustr, "Insert Key%t|Loc%x0|Rot%x1|Size%x2|LocRot%x3|LocRotSize%x4|Layer%x5|Avail%x9");
2348                 }
2349                 
2350                 if(ob) {
2351                         if(ob->type==OB_MESH) strcat(menustr, "| %x6|Mesh%x7");
2352                         else if(ob->type==OB_LATTICE) strcat(menustr, "| %x6|Lattice%x7");
2353                         else if(ob->type==OB_CURVE) strcat(menustr, "| %x6|Curve%x7");
2354                         else if(ob->type==OB_SURF) strcat(menustr, "| %x6|Surface%x7");
2355                 }
2356                 
2357                 event= pupmenu(menustr);
2358                 if(event== -1) return;
2359                 
2360                 if(event==7) { // ob != NULL
2361                         insert_shapekey(ob);
2362                         return;
2363                 }
2364                 
2365                 if (ob && (ob->flag & OB_POSEMODE)){
2366                         bPoseChannel *pchan;
2367
2368                         if (ob->action && ob->action->id.lib) {
2369                                 error ("Can't key libactions");
2370                                 return;
2371                         }
2372                         
2373                         set_pose_keys(ob);  // sets pchan->flag to POSE_KEY if bone selected
2374                         id= &ob->id;
2375                         for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
2376                                 if (pchan->flag & POSE_KEY){
2377                                         if(event==0 || event==3 ||event==4) {
2378                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X);
2379                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y);
2380                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z);
2381                                         }
2382                                         if(event==1 || event==3 ||event==4) {
2383                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
2384                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
2385                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
2386                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
2387                                         }
2388                                         if(event==2 || event==4) {
2389                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X);
2390                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y);
2391                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z);
2392                                         }
2393                                         if (event==9 && ob->action) {
2394                                                 bActionChannel *achan;
2395                                                 
2396                                                 for (achan = ob->action->chanbase.first; achan; achan=achan->next){
2397                                                         if (achan->ipo && !strcmp (achan->name, pchan->name)){
2398                                                                 for (icu = achan->ipo->curve.first; icu; icu=icu->next){
2399                                                                         insertkey(id, ID_PO, achan->name, NULL, icu->adrcode);
2400                                                                 }
2401                                                                 break;
2402                                                         }
2403                                                 }
2404                                         }
2405                                 }
2406                         }
2407                         if(ob->action)
2408                                 remake_action_ipos(ob->action);
2409
2410                         allqueue(REDRAWIPO, 0);
2411                         allqueue(REDRAWACTION, 0);
2412                         allqueue(REDRAWNLA, 0);
2413                 }
2414                 else {
2415                         base= FIRSTBASE;
2416                         while(base) {
2417                                 if TESTBASELIB(base) {
2418                                         char *actname= NULL;
2419                                         
2420                                         id= (ID *)(base->object);
2421                                         
2422                                         if(ob->ipoflag & OB_ACTION_OB)
2423                                                 actname= "Object";
2424                                         
2425                                         /* all curves in ipo deselect */
2426                                         if(base->object->ipo) {
2427                                                 icu= base->object->ipo->curve.first;
2428                                                 while(icu) {
2429                                                         icu->flag &= ~IPO_SELECT;
2430                                                         if(event==9) insertkey(id, ID_OB, actname, NULL, icu->adrcode);
2431                                                         icu= icu->next;
2432                                                 }
2433                                         }
2434                                         
2435                                         if(event==0 || event==3 ||event==4) {
2436                                                 insertkey(id, ID_OB, actname, NULL, OB_LOC_X);
2437                                                 insertkey(id, ID_OB, actname, NULL, OB_LOC_Y);
2438                                                 insertkey(id, ID_OB, actname, NULL, OB_LOC_Z);
2439                                         }
2440                                         if(event==1 || event==3 ||event==4) {
2441                                                 insertkey(id, ID_OB, actname, NULL, OB_ROT_X);
2442                                                 insertkey(id, ID_OB, actname, NULL, OB_ROT_Y);
2443                                                 insertkey(id, ID_OB, actname, NULL, OB_ROT_Z);
2444                                         }
2445                                         if(event==2 || event==4) {
2446                                                 insertkey(id, ID_OB, actname, NULL, OB_SIZE_X);
2447                                                 insertkey(id, ID_OB, actname, NULL, OB_SIZE_Y);
2448                                                 insertkey(id, ID_OB, actname, NULL, OB_SIZE_Z);
2449                                         }
2450                                         if(event==5) {
2451                                                 /* remove localview  */
2452                                                 tlay= base->object->lay;
2453                                                 base->object->lay &= 0xFFFFFF;
2454                                                 insertkey(id, ID_OB, actname, NULL, OB_LAY);
2455                                                 base->object->lay= tlay;
2456                                         }
2457                                 }
2458                                 base= base->next;
2459                         }
2460                 }
2461
2462                 if(event==0) BIF_undo_push("Insert Loc Key");
2463                 else if(event==1) BIF_undo_push("Insert Rot Key");
2464                 else if(event==2) BIF_undo_push("Insert Size Key");
2465                 else if(event==3) BIF_undo_push("Insert LocRot Key");
2466                 else if(event==4) BIF_undo_push("Insert LocRotSize Key");
2467                 else if(event==5) BIF_undo_push("Insert Layer Key");
2468                 else if(event==7) BIF_undo_push("Insert Vertex Key");
2469                 else if(event==9) BIF_undo_push("Insert Avail Key");
2470
2471                 allspace(REMAKEIPO, 0);
2472                 allqueue(REDRAWIPO, 0);
2473                 allqueue(REDRAWVIEW3D, 0);
2474                 allqueue(REDRAWACTION, 0);
2475                 allqueue(REDRAWNLA, 0);
2476         }
2477         
2478 }
2479
2480 /* ****************************************************************************** */
2481
2482 void add_duplicate_editipo(void)
2483 {
2484         Object *ob;
2485         EditIpo *ei;
2486         IpoCurve *icu;
2487         BezTriple *bezt, *beztn, *newb;
2488         int tot, a, b;
2489         
2490         get_status_editipo();
2491         if(totipo_vertsel==0) return;
2492         
2493         ei= G.sipo->editipo;
2494         for(a=0; a<G.sipo->totipo; a++, ei++) {
2495                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2496                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2497                                 icu= ei->icu;
2498                                 
2499                                 /* how many points */
2500                                 tot= 0;
2501                                 b= icu->totvert;
2502                                 bezt= icu->bezt;
2503                                 while(b--) {
2504                                         if(bezt->f2 & 1) tot++;
2505                                         bezt++;
2506                                 }
2507                                 
2508                                 if(tot) {
2509                                         icu->totvert+= tot;
2510                                         newb= beztn= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2511                                         bezt= icu->bezt;
2512                                         b= icu->totvert-tot;
2513                                         while(b--) {
2514                                                 *beztn= *bezt;
2515                                                 if(bezt->f2 & 1) {
2516                                                         beztn->f1= beztn->f2= beztn->f3= 0;
2517                                                         beztn++;
2518                                                         *beztn= *bezt;
2519                                                 }
2520                                                 beztn++;
2521                                                 bezt++;
2522                                         }
2523                                         MEM_freeN(icu->bezt);
2524                                         icu->bezt= newb;
2525                                         
2526                                         calchandles_ipocurve(icu);
2527                                 }
2528                         }
2529                 }
2530         }
2531         
2532         if(G.sipo->showkey) {
2533                 make_ipokey();
2534                 if(G.sipo->blocktype==ID_OB) {
2535                         ob= OBACT;
2536                         if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
2537                 }
2538         }
2539         BIF_undo_push("Duplicate Ipo");
2540         transform_ipo('g');
2541 }
2542
2543 void remove_doubles_ipo(void)
2544 {
2545         EditIpo *ei;
2546         IpoKey *ik, *ikn;
2547         BezTriple *bezt, *newb, *new1;
2548         float val;
2549         int mode, a, b;
2550         
2551         ei= G.sipo->editipo;
2552         for(a=0; a<G.sipo->totipo; a++, ei++) {
2553                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2554                         
2555                         /* OR the curve is selected OR in editmode OR in keymode */
2556                         mode= 0;
2557                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) mode= 1;
2558                         else if(ei->flag & IPO_SELECT) mode= 2;
2559                         
2560                         if(mode) {
2561                                 bezt= ei->icu->bezt;
2562                                 newb= new1= MEM_mallocN(ei->icu->totvert*sizeof(BezTriple), "newbezt");
2563                                 *newb= *bezt;
2564                                 b= ei->icu->totvert-1;
2565                                 bezt++;
2566                                 while(b--) {
2567                                         
2568                                         /* can we remove? */
2569                                         if(mode==2 || (bezt->f2 & 1)) {
2570                                         
2571                                                 /* are the points different? */
2572                                                 if( fabs( bezt->vec[1][0]-newb->vec[1][0] ) > 0.9 ) {
2573                                                         newb++;
2574                                                         *newb= *bezt;
2575                                                 }
2576                                                 else {
2577                                                         /* median */
2578                                                         VecMidf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2579                                                         VecMidf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2580                                                         VecMidf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2581                                                         
2582                                                         newb->h1= newb->h2= HD_FREE;
2583                                                         
2584                                                         ei->icu->totvert--;
2585                                                 }
2586                                                 
2587                                         }
2588                                         else {
2589                                                 newb++;
2590                                                 *newb= *bezt;
2591                                         }
2592                                         bezt++;
2593                                 }
2594                                 
2595                                 MEM_freeN(ei->icu->bezt);
2596                                 ei->icu->bezt= new1;
2597                                 
2598                                 calchandles_ipocurve(ei->icu);                          
2599                         }
2600                 }
2601         }
2602         
2603         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2604
2605         /* remove double keys */
2606         if(G.sipo->showkey) {
2607                 ik= G.sipo->ipokey.first;
2608                 ikn= ik->next;
2609                 
2610                 while(ik && ikn) {
2611                         if( (ik->flag & 1) && (ikn->flag & 1) ) {
2612                                 if( fabs(ik->val-ikn->val) < 0.9 ) {
2613                                         val= (float)((ik->val + ikn->val)/2.0);
2614                                         
2615                                         for(a=0; a<G.sipo->totipo; a++) {
2616                                                 if(ik->data[a]) ik->data[a]->vec[1][0]= val;
2617                                                 if(ikn->data[a]) ikn->data[a]->vec[1][0]= val;                                          
2618                                         }
2619                                 }
2620                         }
2621                         ik= ikn;
2622                         ikn= ikn->next;
2623
2624                 }
2625                 
2626                 editipo_changed(G.sipo, 1);     /* makes ipokeys agian! */
2627
2628         }
2629         deselectall_editipo();
2630 }
2631
2632 void join_ipo_menu(void)
2633 {
2634         int mode = 0;
2635         mode= pupmenu("Join %t|All Selected %x1|Selected Doubles %x2");
2636         
2637         if (mode == -1) return;
2638         
2639         join_ipo(mode);
2640 }
2641
2642 void join_ipo(int mode)
2643 {
2644         EditIpo *ei;
2645         IpoKey *ik;
2646         IpoCurve *icu;
2647         BezTriple *bezt, *beztn, *newb;
2648         float val;
2649         int tot, a, b;
2650         
2651         get_status_editipo();
2652         
2653         /* Mode events:
2654          * All Selected: 1
2655          * Selected Doubles: 2
2656          */
2657         
2658         if( mode==2 ) {
2659                 remove_doubles_ipo();
2660                 return;
2661         }
2662         
2663         /* first: multiple selected verts in 1 curve */
2664         ei= G.sipo->editipo;
2665         for(a=0; a<G.sipo->totipo; a++, ei++) {
2666                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2667                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2668                                 icu= ei->icu;
2669                                 
2670                                 /* how many points */
2671                                 tot= 0;
2672                                 b= icu->totvert;
2673                                 bezt= icu->bezt;
2674                                 while(b--) {
2675                                         if(bezt->f2 & 1) tot++;
2676                                         bezt++;
2677                                 }
2678                                 
2679                                 if(tot>1) {
2680                                         tot--;
2681                                         icu->totvert-= tot;
2682                                         
2683                                         newb= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2684                                         /* the first point is the new one */
2685                                         beztn= newb+1;
2686                                         tot= 0;
2687                                         
2688                                         bezt= icu->bezt;
2689                                         b= icu->totvert+tot+1;
2690                                         while(b--) {
2691                                                 
2692                                                 if(bezt->f2 & 1) {
2693                                                         if(tot==0) *newb= *bezt;
2694                                                         else {
2695                                                                 VecAddf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2696                                                                 VecAddf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2697                                                                 VecAddf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2698                                                         }
2699                                                         tot++;
2700                                                 }
2701                                                 else {
2702                                                         *beztn= *bezt;
2703                                                         beztn++;
2704                                                 }
2705                                                 bezt++;
2706                                         }
2707                                         
2708                                         VecMulf(newb->vec[0], (float)(1.0/((float)tot)));
2709                                         VecMulf(newb->vec[1], (float)(1.0/((float)tot)));
2710                                         VecMulf(newb->vec[2], (float)(1.0/((float)tot)));
2711                                         
2712                                         MEM_freeN(icu->bezt);
2713                                         icu->bezt= newb;
2714                                         
2715                                         sort_time_ipocurve(icu);
2716                                         calchandles_ipocurve(icu);
2717                                 }
2718                         }
2719                 }
2720         }
2721         
2722         /* next: in keymode: join multiple selected keys */
2723         
2724         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2725         
2726         if(G.sipo->showkey) {
2727                 ik= G.sipo->ipokey.first;
2728                 val= 0.0;
2729                 tot= 0;
2730                 while(ik) {
2731                         if(ik->flag & 1) {
2732                                 for(a=0; a<G.sipo->totipo; a++) {
2733                                         if(ik->data[a]) {
2734                                                 val+= ik->data[a]->vec[1][0];
2735                                                 break;
2736                                         }
2737                                 }
2738                                 tot++;
2739                         }
2740                         ik= ik->next;
2741                 }
2742                 if(tot>1) {
2743                         val/= (float)tot;
2744                         
2745                         ik= G.sipo->ipokey.first;
2746                         while(ik) {
2747                                 if(ik->flag & 1) {
2748                                         for(a=0; a<G.sipo->totipo; a++) {
2749                                                 if(ik->data[a]) {
2750                                                         ik->data[a]->vec[1][0]= val;
2751                                                 }
2752                                         }
2753                                 }
2754                                 ik= ik->next;
2755                         }
2756                         editipo_changed(G.sipo, 0);
2757                 }
2758         }
2759         deselectall_editipo();
2760         BIF_undo_push("Join Ipo");
2761 }
2762
2763 void ipo_snap_menu(void)
2764 {
2765         short event;
2766         
2767         event= pupmenu("Snap %t|Horizontal %x1|To Next %x2|To Frame %x3|To Current Frame%x4");
2768         if(event < 1) return;
2769
2770         ipo_snap(event);
2771 }
2772
2773 void ipo_snap(short event)
2774 {
2775         EditIpo *ei;
2776         BezTriple *bezt;
2777         float dx = 0.0;
2778         int a, b;
2779         short ok, ok2;
2780         
2781         /* events:
2782          * Horizontal : 1
2783          * To Next: 2
2784          * To Frame: 3
2785          * To Current Frame: 4
2786          */
2787          
2788         get_status_editipo();
2789
2790         ei= G.sipo->editipo;
2791         for(b=0; b<G.sipo->totipo; b++, ei++) {
2792                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2793                 
2794                         ok2= 0;
2795                         if(G.sipo->showkey) ok2= 1;
2796                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok2= 2;
2797                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok2= 3;
2798                         
2799                         if(ok2) {
2800                                 bezt= ei->icu->bezt;
2801                                 a= ei->icu->totvert;
2802                                 while(a--) {
2803                                         ok= 0;
2804                                         if(totipo_vert) {
2805                                                  if(bezt->f2 & 1) ok= 1;
2806                                         }
2807                                         else ok= 1;
2808                                         
2809                                         if(ok) {
2810                                                 if(event==1) {
2811                                                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
2812                                                         if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2813                                                         if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2814                                                 }
2815                                                 else if(event==2) {
2816                                                         if(a) {
2817                                                                 bezt->vec[0][1]= bezt->vec[1][1]= bezt->vec[2][1]= (bezt+1)->vec[1][1];
2818                                                                 if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2819                                                                 if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2820                                                         }
2821                                                 }
2822                                                 else if(event==3) {
2823                                                         bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
2824                                                 }
2825                                                 else if(event==4) {     /* to current frame */
2826                                                         
2827                                                         if(ok2==1 || ok2==2) {
2828                                                                 
2829                                                                 if(G.sipo->blocktype==ID_SEQ) {
2830                                                                         Sequence *seq;
2831                                                         
2832                                                                         seq= (Sequence *)G.sipo->from;
2833                                                                         if(seq) {
2834                                                                                 dx= (float)(CFRA-seq->startdisp);
2835                                                                                 dx= (float)(100.0*dx/((float)(seq->enddisp-seq->startdisp)));
2836                                                                                 
2837                                                                                 dx-= bezt->vec[1][0];
2838                                                                         }
2839                                                                 }
2840                                                                 else dx= G.scene->r.framelen*CFRA - bezt->vec[1][0];
2841                                                                 
2842                                                                 bezt->vec[0][0]+= dx;
2843                                                                 bezt->vec[1][0]+= dx;
2844                                                                 bezt->vec[2][0]+= dx;
2845                                                         }
2846                                                 }
2847                                         }
2848                                         
2849                                         bezt++;
2850                                 }
2851                                 calchandles_ipocurve(ei->icu);
2852                         }
2853                 }
2854         }
2855         editipo_changed(G.sipo, 1);
2856         BIF_undo_push("Snap Ipo");
2857 }
2858
2859 /*
2860  * When deleting an IPO curve from Python, check if the Ipo is being
2861  * edited and if so clear the pointer to the old curve.
2862  */
2863
2864 void del_ipoCurve ( IpoCurve * icu )
2865 {
2866         int i;
2867         EditIpo *ei= G.sipo->editipo;
2868         if (!ei) return;
2869
2870         for(i=0; i<G.sipo->totipo; i++, ei++) {
2871                 if ( ei->icu == icu ) {
2872                         ei->flag &= ~(IPO_SELECT | IPO_EDIT);
2873                         ei->icu= NULL;
2874                         return;
2875                 }
2876         }
2877 }
2878
2879 void del_ipo(void)
2880 {
2881         EditIpo *ei;
2882         BezTriple *bezt, *bezt1;
2883         int a, b;
2884         int del, event;
2885
2886         get_status_editipo();
2887         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
2888         
2889         if(totipo_edit==0 && totipo_sel==0 && totipo_vertsel==0) {
2890                 if(okee("Erase selected keys"))
2891                    delete_key(OBACT);
2892                 return;
2893         }
2894         
2895         if( okee("Erase selected")==0 ) return;
2896
2897         // first round, can we delete entire parts? 
2898         ei= G.sipo->editipo;
2899         for(a=0; a<G.sipo->totipo; a++, ei++) {
2900         
2901                 del= 0;
2902                 
2903                 if(G.sipo->showkey==0 && totipo_edit==0) {
2904                         if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
2905                                 del= 1;
2906                         }
2907                 }
2908                 else {
2909                         if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
2910                                 if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2911                                         if(ei->icu->bezt) {