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