Removed DAG update for armature after inserting keys in pose mode.
[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(GS(from->name)!=ID_OB) {
1587                         printf("called ipo system for action with wrong base pointer\n");
1588                         return NULL;
1589                 }
1590                 
1591                 if(ob->action==NULL)
1592                         ob->action= add_empty_action(blocktype);
1593                 
1594                 achan= verify_action_channel(ob->action, actname);
1595                 
1596                 if(achan) {
1597                         /* constraint exception */
1598                         if(blocktype==ID_CO) {
1599                                 bConstraintChannel *conchan= verify_constraint_channel(&achan->constraintChannels, constname);
1600                                 if(conchan->ipo==NULL) {
1601                                         conchan->ipo= add_ipo("CoIpo", ID_CO);  
1602                                 }
1603                                 return conchan->ipo;
1604                         }
1605                         else {
1606                                 if(achan->ipo==NULL) {
1607                                         achan->ipo= add_ipo("ActIpo", blocktype);
1608                                 }
1609                                 
1610                                 return achan->ipo;
1611                         }
1612                 }
1613         }
1614         else {
1615                 
1616                 switch(GS(from->name)) {
1617                 case ID_OB:
1618                         {
1619                                 Object *ob= (Object *)from;
1620                                 /* constraint exception */
1621                                 if(blocktype==ID_CO) {
1622                                         bConstraintChannel *conchan= verify_constraint_channel(&ob->constraintChannels, constname);
1623                                         if(conchan->ipo==NULL) {
1624                                                 conchan->ipo= add_ipo("CoIpo", ID_CO);  
1625                                         }
1626                                         return conchan->ipo;
1627                                 }
1628                                 else if(blocktype==ID_OB) {
1629                                         if(ob->ipo==NULL) {
1630                                                 ob->ipo= add_ipo("ObIpo", ID_OB);
1631                                         }
1632                                         return ob->ipo;
1633                                 }
1634                         }
1635                         break;
1636                 case ID_MA:
1637                         {
1638                                 Material *ma= (Material *)from;
1639
1640                                 if(ma->ipo==NULL) {
1641                                         ma->ipo= add_ipo("MatIpo", ID_MA);
1642                                 }
1643                                 return ma->ipo;
1644                         }
1645                         break;
1646                 case ID_TE:
1647                         {
1648                                 Tex *tex= (Tex *)from;
1649
1650                                 if(tex->ipo==NULL) {
1651                                         tex->ipo= add_ipo("TexIpo", ID_TE);
1652                                 }
1653                                 return tex->ipo;
1654                         }
1655                         break;
1656                 case ID_SEQ:
1657                         {
1658                                 Sequence *seq= (Sequence *)from;        /* note, sequence is mimicing Id */
1659
1660                                 if((seq->type & SEQ_EFFECT)||(seq->type == SEQ_SOUND)) {
1661                                         if(seq->ipo==NULL) {
1662                                                 seq->ipo= add_ipo("SeqIpo", ID_SEQ);
1663                                         }
1664                                         return seq->ipo;
1665                                 }
1666                         }
1667                         break;
1668                 case ID_CU:
1669                         {
1670                                 Curve *cu= (Curve *)from;
1671                                 
1672                                 if(cu->ipo==NULL) {
1673                                         cu->ipo= add_ipo("CuIpo", ID_CU);
1674                                 }
1675                                 return cu->ipo;
1676                         }
1677                         break;
1678                 case ID_KE:
1679                         {
1680                                 Key *key= (Key *)from;
1681
1682                                 if(key->ipo==NULL) {
1683                                         key->ipo= add_ipo("KeyIpo", ID_KE);
1684                                 }
1685                                 return key->ipo;
1686                         }
1687                         break;
1688                 case ID_WO:
1689                         {
1690                                 World *wo= (World *)from;
1691
1692                                 if(wo->ipo==NULL) {
1693                                         wo->ipo= add_ipo("WoIpo", ID_WO);
1694                                 }
1695                                 return wo->ipo;
1696                         }
1697                         break;
1698                 case ID_LA:
1699                         {
1700                                 Lamp *la= (Lamp *)from;
1701                                 
1702                                 if(la->ipo==NULL) {
1703                                         la->ipo= add_ipo("LaIpo", ID_LA);
1704                                 }
1705                                 return la->ipo;
1706                         }
1707                         break;
1708                 case ID_CA:
1709                         {
1710                                 Camera *ca= (Camera *)from;
1711
1712                                 if(ca->ipo==NULL) {
1713                                         ca->ipo= add_ipo("CaIpo", ID_CA);
1714                                 }
1715                                 return ca->ipo;
1716                         }
1717                         break;
1718                 case ID_SO:
1719                         {
1720                                 bSound *snd= (bSound *)from;
1721
1722                                 if(snd->ipo==NULL) {
1723                                         snd->ipo= add_ipo("SndIpo", ID_SO);
1724                                 }
1725                                 return snd->ipo;
1726                         }
1727                 }
1728         }
1729         
1730         return NULL;    
1731 }
1732
1733 /* returns and creates */
1734 IpoCurve *verify_ipocurve(ID *from, short blocktype, char *actname, char *constname, int adrcode)
1735 {
1736         Ipo *ipo;
1737         IpoCurve *icu= NULL;
1738         
1739         /* return 0 if lib */
1740         /* creates ipo too */
1741         ipo= verify_ipo(from, blocktype, actname, constname);
1742         
1743         if(ipo && ipo->id.lib==NULL) {
1744                 
1745                 for(icu= ipo->curve.first; icu; icu= icu->next) {
1746                         if(icu->adrcode==adrcode) break;
1747                 }
1748                 if(icu==NULL) {
1749                         icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
1750
1751                         icu->flag |= IPO_VISIBLE|IPO_AUTO_HORIZ;
1752                         icu->blocktype= blocktype;
1753                         icu->adrcode= adrcode;
1754                         
1755                         set_icu_vars(icu);
1756                         
1757                         BLI_addtail( &(ipo->curve), icu);
1758                 }
1759         }
1760
1761         return icu;
1762 }
1763
1764 void insert_vert_ipo(IpoCurve *icu, float x, float y)
1765 {
1766         BezTriple *bezt, beztr, *newbezt;
1767         int a = 0, h1, h2;
1768         
1769         memset(&beztr, 0, sizeof(BezTriple));
1770         beztr.vec[0][0]= x; // set all three points, for nicer start position
1771         beztr.vec[0][1]= y;
1772         beztr.vec[1][0]= x;
1773         beztr.vec[1][1]= y;
1774         beztr.vec[2][0]= x;
1775         beztr.vec[2][1]= y;
1776         beztr.hide= IPO_BEZ;
1777         beztr.f1= beztr.f2= beztr.f3= SELECT;
1778         beztr.h1= beztr.h2= HD_AUTO;
1779                 
1780         bezt= icu->bezt;
1781                 
1782         if(bezt==NULL) {
1783                 icu->bezt= MEM_callocN( sizeof(BezTriple), "beztriple");
1784                 *(icu->bezt)= beztr;
1785                 icu->totvert= 1;
1786         }
1787         else {
1788                 /* all vertices deselect */
1789                 for(a=0; a<icu->totvert; a++, bezt++) {
1790                         bezt->f1= bezt->f2= bezt->f3= 0;
1791                 }
1792         
1793                 bezt= icu->bezt;
1794                 for(a=0; a<=icu->totvert; a++, bezt++) {
1795                         
1796                         /* no double points */
1797                         if(a<icu->totvert && (bezt->vec[1][0]>x-IPOTHRESH && bezt->vec[1][0]<x+IPOTHRESH)) {
1798                                 *(bezt)= beztr;
1799                                 break;
1800                         }
1801                         if(a==icu->totvert || bezt->vec[1][0] > x) {
1802                                 newbezt= MEM_callocN( (icu->totvert+1)*sizeof(BezTriple), "beztriple");
1803                                 
1804                                 if(a>0) memcpy(newbezt, icu->bezt, a*sizeof(BezTriple));
1805                                 
1806                                 bezt= newbezt+a;
1807                                 *(bezt)= beztr;
1808                                 
1809                                 if(a<icu->totvert) memcpy(newbezt+a+1, icu->bezt+a, (icu->totvert-a)*sizeof(BezTriple));
1810                                 
1811                                 MEM_freeN(icu->bezt);
1812                                 icu->bezt= newbezt;
1813                                 
1814                                 icu->totvert++;
1815                                 break;
1816                         }
1817                 }
1818         }
1819         
1820         
1821         calchandles_ipocurve(icu);
1822         
1823         /* set handletype */
1824         if(icu->totvert>2) {
1825                 h1= h2= HD_AUTO;
1826                 if(a>0) h1= (bezt-1)->h2;
1827                 if(a<icu->totvert-1) h2= (bezt+1)->h1;
1828                 bezt->h1= h1;
1829                 bezt->h2= h2;
1830
1831                 calchandles_ipocurve(icu);
1832         }
1833 }
1834
1835 void add_vert_ipo(void)
1836 {
1837         EditIpo *ei;
1838         float x, y;
1839         int val;
1840         short mval[2];
1841
1842         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1843         if(G.sipo->showkey) {
1844                 G.sipo->showkey= 0;
1845                 free_ipokey(&G.sipo->ipokey);
1846         }
1847         
1848         getmouseco_areawin(mval);
1849         
1850         if(mval[0]>G.v2d->mask.xmax) return;
1851         
1852         ei= get_active_editipo();
1853         if(ei==0) {
1854                 error("No active Ipo curve");
1855                 return;
1856         }
1857         
1858         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1859         
1860         if(ei->icu==NULL) {
1861                 if(G.sipo->from) {
1862                         ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei->adrcode);
1863                         ei->flag |= ei->icu->flag & IPO_AUTO_HORIZ;     /* new curve could have been added, weak... */
1864                 }
1865         }
1866         if(ei->icu==NULL) return;
1867
1868         if(ei->disptype==IPO_DISPBITS) {
1869                 ei->icu->vartype= IPO_BITS;
1870                 val= (int)floor(y-0.5);
1871                 if(val<0) val= 0;
1872                 y= (float)(1 << val);
1873         }
1874         
1875         insert_vert_ipo(ei->icu, x, y);
1876
1877         /* to be sure: if icu was 0, or only 1 curve visible */
1878         ei->flag |= IPO_SELECT;
1879         ei->icu->flag= ei->flag;
1880         
1881         editipo_changed(G.sipo, 1);
1882         BIF_undo_push("Add Ipo vertex");
1883 }
1884
1885 static void *get_context_ipo_poin(ID *id, int blocktype, char *actname, IpoCurve *icu, int *vartype)
1886 {
1887         if(blocktype==ID_PO) {
1888                 if(GS(id->name)==ID_OB) {
1889                         Object *ob= (Object *)id;
1890                         bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
1891                         
1892                         *vartype= IPO_FLOAT;
1893                         return get_pchan_ipo_poin(pchan, icu->adrcode);
1894                 }
1895                 return NULL;
1896         }
1897         else
1898                 return get_ipo_poin(id, icu, vartype);
1899
1900 }
1901
1902 void insertkey(ID *id, int blocktype, char *actname, char *constname, int adrcode)
1903 {
1904         IpoCurve *icu;
1905         Object *ob;
1906         void *poin= NULL;
1907         float curval, cfra;
1908         int vartype;
1909         
1910         icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
1911         
1912         if(icu) {
1913                 
1914                 poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
1915                 
1916                 if(poin) {
1917                         curval= read_ipo_poin(poin, vartype);
1918                         
1919                         cfra= frame_to_float(CFRA);
1920                         
1921                         /* if action is mapped in NLA, it returns a correction */
1922                         if(actname && actname[0] && GS(id->name)==ID_OB)
1923                                 cfra= get_action_frame((Object *)id, cfra);
1924                         
1925                         if( GS(id->name)==ID_OB ) {
1926                                 ob= (Object *)id;
1927                                 if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
1928                                         /* actually frametofloat calc again! */
1929                                         cfra-= ob->sf*G.scene->r.framelen;
1930                                 }
1931                         }
1932                         
1933                         insert_vert_ipo(icu, cfra, curval);
1934                 }
1935         }
1936 }
1937
1938 void insertkey_editipo(void)
1939 {
1940         EditIpo *ei;
1941         IpoKey *ik;
1942         ID *id;
1943         float *fp, cfra, *insertvals;
1944         int a, nr, ok, tot;
1945         short event;
1946         
1947         ei= get_active_editipo();
1948         if(ei && ei->icu && ei->icu->driver) 
1949                 event= pupmenu("Insert Curve %t|Default one-to-one mapping %x3");
1950         else if(G.sipo->showkey)
1951                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1|Selected Keys %x2");
1952         else 
1953                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1");
1954         
1955         if(event<1) return;
1956         
1957         if(event==3) {
1958                 IpoDriver *driver= ei->icu->driver;
1959                 
1960                 if(ei->icu->bezt) MEM_freeN(ei->icu->bezt);
1961                 ei->icu->totvert= 0;
1962                 ei->icu->bezt= NULL;
1963                 
1964                 insert_vert_ipo(ei->icu, 0.0f, 0.0f);
1965                 
1966                 if(ELEM3(driver->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
1967                         if(ei->disptype==IPO_DISPDEGR)
1968                                 insert_vert_ipo(ei->icu, 18.0f, 18.0f);
1969                         else
1970                                 insert_vert_ipo(ei->icu, 18.0f, 1.0f);
1971                 }
1972                 else
1973                         insert_vert_ipo(ei->icu, 1.0f, 1.0f);
1974                 
1975                 ei->flag |= IPO_SELECT|IPO_VISIBLE;
1976                 ei->icu->flag= ei->flag;
1977                 ei->icu->extrap= IPO_DIR;
1978
1979                 do_ipo_buttons(B_IPOHOME);
1980         }
1981         else {
1982                 ei= G.sipo->editipo;
1983                 for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
1984                         if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
1985                         
1986                                 ok= 0;
1987                                 if(G.sipo->showkey) ok= 1;
1988                                 else if(ei->flag & IPO_SELECT) ok= 1;
1989
1990                                 if(ok) {
1991                                         /* count amount */
1992                                         if(event==1) tot= 1;
1993                                         else {
1994                                                 ik= G.sipo->ipokey.first;
1995                                                 tot= 0;
1996                                                 while(ik) {
1997                                                         if(ik->flag & 1) tot++;
1998                                                         ik= ik->next;
1999                                                 }
2000                                         }
2001                                         if(tot) {
2002                                         
2003                                                 /* correction for ob timeoffs */
2004                                                 cfra= frame_to_float(CFRA);
2005                                                 id= G.sipo->from;       
2006                                                 if(id && GS(id->name)==ID_OB ) {
2007                                                         Object *ob= (Object *)id;
2008                                                         if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
2009                                                                 cfra-= ob->sf*G.scene->r.framelen;
2010                                                         }
2011                                                 }
2012                                                 else if(id && GS(id->name)==ID_SEQ) {
2013                                                         extern Sequence *last_seq;      /* editsequence.c */
2014                                                         
2015                                                         if(last_seq) {
2016                                                                 cfra= (float)(100.0*(cfra-last_seq->startdisp)/((float)(last_seq->enddisp-last_seq->startdisp)));
2017                                                         }
2018                                                 }
2019                                 
2020                                                 insertvals= MEM_mallocN(sizeof(float)*2*tot, "insertkey_editipo");
2021                                                 /* make sure icu->curval is correct */
2022                                                 calc_ipo(G.sipo->ipo, cfra);
2023                                                 
2024                                                 if(event==1) {
2025                                                         insertvals[0]= cfra;
2026                                                         
2027                                                         insertvals[1]= ei->icu->curval;
2028                                                 }
2029                                                 else {
2030                                                         fp= insertvals;
2031                                                         ik= G.sipo->ipokey.first;
2032                                                         while(ik) {
2033                                                                 if(ik->flag & 1) {
2034                                                                         calc_ipo(G.sipo->ipo, ik->val);
2035
2036                                                                         fp[0]= ik->val;
2037                                                                         fp[1]= ei->icu->curval;
2038                                                                         fp+= 2;
2039                                                                 }
2040                                                                 ik= ik->next;
2041                                                         }
2042                                                 }
2043                                                 fp= insertvals;
2044                                                 for(a=0; a<tot; a++, fp+=2) {
2045                                                         insert_vert_ipo(ei->icu, fp[0], fp[1]);
2046                                                 }
2047                                                 
2048                                                 MEM_freeN(insertvals);
2049                                                 calc_ipo(G.sipo->ipo, (float)CFRA);
2050                                         }
2051                                 }
2052                         }
2053                 }
2054         }
2055         BIF_undo_push("Insert Key Ipo");
2056         allqueue (REDRAWACTION, 0);
2057         allqueue(REDRAWNLA, 0);
2058         allqueue(REDRAWIPO, 0);
2059         allspace(REMAKEIPO, 0);
2060 }
2061
2062
2063 void common_insertkey(void)
2064 {
2065         Base *base;
2066         Object *ob;
2067         Material *ma;
2068         ID *id;
2069         IpoCurve *icu;
2070         World *wo;
2071         Lamp *la;
2072         int tlay, map, event;
2073         char menustr[256];
2074         
2075         if(curarea->spacetype==SPACE_IPO) {
2076                 insertkey_editipo();
2077         }
2078         else if(curarea->spacetype==SPACE_BUTS) {
2079                 if(G.buts->mainb==CONTEXT_SHADING) {
2080                         int tab= G.buts->tab[CONTEXT_SHADING];
2081                         
2082                         if(tab==TAB_SHADING_MAT) {
2083                                 id= G.buts->lockpoin;
2084                                 ma= G.buts->lockpoin;
2085                                 if(id) {
2086                                         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");
2087                                         if(event== -1) return;
2088                                         
2089                                         map= texchannel_to_adrcode(ma->texact);
2090                                         
2091                                         if(event==0 || event==10) {
2092                                                 insertkey(id, ID_MA, NULL, NULL, MA_COL_R);
2093                                                 insertkey(id, ID_MA, NULL, NULL, MA_COL_G);
2094                                                 insertkey(id, ID_MA, NULL, NULL, MA_COL_B);
2095                                         }
2096                                         if(event==1 || event==10) {
2097                                                 insertkey(id, ID_MA, NULL, NULL, MA_ALPHA);
2098                                         }
2099                                         if(event==2 || event==10) {
2100                                                 insertkey(id, ID_MA, NULL, NULL, MA_HASIZE);
2101                                         }
2102                                         if(event==3 || event==10) {
2103                                                 insertkey(id, ID_MA, NULL, NULL, MA_MODE);
2104                                         }
2105                                         if(event==10) {
2106                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC_R);
2107                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC_G);
2108                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC_B);
2109                                                 insertkey(id, ID_MA, NULL, NULL, MA_REF);
2110                                                 insertkey(id, ID_MA, NULL, NULL, MA_EMIT);
2111                                                 insertkey(id, ID_MA, NULL, NULL, MA_AMB);
2112                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC);
2113                                                 insertkey(id, ID_MA, NULL, NULL, MA_HARD);
2114                                                 insertkey(id, ID_MA, NULL, NULL, MA_MODE);
2115                                                 insertkey(id, ID_MA, NULL, NULL, MA_TRANSLU);
2116                                                 insertkey(id, ID_MA, NULL, NULL, MA_ADD);
2117                                         }
2118                                         if(event==14) {
2119                                                 insertkey(id, ID_MA, NULL, NULL, MA_RAYM);
2120                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESMIR);
2121                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESMIRI);
2122                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESTRA);
2123                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESTRAI);
2124                                         }
2125                                         if(event==12 || event==11) {
2126                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_X);
2127                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_Y);
2128                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_Z);
2129                                         }
2130                                         if(event==13 || event==11) {
2131                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_X);
2132                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_Y);
2133                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_Z);
2134                                         }
2135                                         if(event==11) {
2136                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_R);
2137                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_G);
2138                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_B);
2139                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_DVAR);
2140                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_COLF);
2141                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_NORF);
2142                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_VARF);
2143                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_DISP);
2144                                         }
2145                                 }
2146                         }
2147                         else if(tab==TAB_SHADING_WORLD) {
2148                                 id= G.buts->lockpoin;
2149                                 wo= G.buts->lockpoin;
2150                                 if(id) {
2151                                         event= pupmenu("Insert Key %t|Zenith RGB%x0|Horizon RGB%x1|Mist%x2|Stars %x3|Offset%x12|Size%x13");
2152                                         if(event== -1) return;
2153                                         
2154                                         map= texchannel_to_adrcode(wo->texact);
2155                                         
2156                                         if(event==0) {
2157                                                 insertkey(id, ID_WO, NULL, NULL, WO_ZEN_R);
2158                                                 insertkey(id, ID_WO, NULL, NULL, WO_ZEN_G);
2159                                                 insertkey(id, ID_WO, NULL, NULL, WO_ZEN_B);
2160                                         }
2161                                         if(event==1) {
2162                                                 insertkey(id, ID_WO, NULL, NULL, WO_HOR_R);
2163                                                 insertkey(id, ID_WO, NULL, NULL, WO_HOR_G);
2164                                                 insertkey(id, ID_WO, NULL, NULL, WO_HOR_B);
2165                                         }
2166                                         if(event==2) {
2167                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISI);
2168                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISTDI);
2169                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISTSTA);
2170                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISTHI);
2171                                         }
2172                                         if(event==3) {
2173                                                 insertkey(id, ID_WO, NULL, NULL, WO_STAR_R);
2174                                                 insertkey(id, ID_WO, NULL, NULL, WO_STAR_G);
2175                                                 insertkey(id, ID_WO, NULL, NULL, WO_STAR_B);
2176                                                 insertkey(id, ID_WO, NULL, NULL, WO_STARDIST);
2177                                                 insertkey(id, ID_WO, NULL, NULL, WO_STARSIZE);
2178                                         }
2179                                         if(event==12) {
2180                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_X);
2181                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_Y);
2182                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_Z);
2183                                         }
2184                                         if(event==13) {
2185                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_X);
2186                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_Y);
2187                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_Z);
2188                                         }
2189                                 }
2190                         }
2191                         else if(tab==TAB_SHADING_LAMP) {
2192                                 id= G.buts->lockpoin;
2193                                 la= G.buts->lockpoin;
2194                                 if(id) {
2195                                         event= pupmenu("Insert Key %t|RGB%x0|Energy%x1|Spot Size%x2|Offset%x12|Size%x13");
2196                                         if(event== -1) return;
2197                                         
2198                                         map= texchannel_to_adrcode(la->texact);
2199                                         
2200                                         if(event==0) {
2201                                                 insertkey(id, ID_LA, NULL, NULL, LA_COL_R);
2202                                                 insertkey(id, ID_LA, NULL, NULL, LA_COL_G);
2203                                                 insertkey(id, ID_LA, NULL, NULL, LA_COL_B);
2204                                         }
2205                                         if(event==1) {
2206                                                 insertkey(id, ID_LA, NULL, NULL, LA_ENERGY);
2207                                         }
2208                                         if(event==2) {
2209                                                 insertkey(id, ID_LA, NULL, NULL, LA_SPOTSI);
2210                                         }
2211                                         if(event==12) {
2212                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_X);
2213                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_Y);
2214                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_Z);
2215                                         }
2216                                         if(event==13) {
2217                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_X);
2218                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_Y);
2219                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_Z);
2220                                         }
2221
2222                                 }
2223                         }
2224                 }
2225                 else if(G.buts->mainb==CONTEXT_OBJECT) {
2226                         ob= OBACT;
2227                         if(ob && ob->type==OB_MESH) {
2228                                 id= (ID *) (ob);
2229                                 if(id) {
2230                                         event= pupmenu("Insert Key %t|Surface Damping%x0|Random Damping%x1|Permeability%x2|Force Strength%x3|Force Falloff%x4");
2231                                         if(event== -1) return;
2232
2233                                         if(event==0) {
2234                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_SDAMP);
2235                                         }
2236                                         if(event==1) {
2237                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_RDAMP);
2238                                         }
2239                                         if(event==2) {
2240                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_PERM);
2241                                         }
2242                                         if(event==3) {
2243                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_FSTR);
2244                                         }
2245                                         if(event==4) {
2246                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_FFALL);
2247                                         }
2248
2249                                 }
2250                         }
2251                 }
2252                 else if(G.buts->mainb==CONTEXT_EDITING) {
2253                         ob= OBACT;
2254                         if(ob && ob->type==OB_CAMERA) {
2255                                 id= G.buts->lockpoin;
2256                                 if(id) {
2257                                         /* yafray: insert key extended with aperture and focal distance */
2258                                         if (G.scene->r.renderer==R_INTERN)
2259                                                 event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1");
2260                                         else
2261                                                 event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1|Aperture%x2|FocalDistance%x3");
2262                                         if(event== -1) return;
2263
2264                                         if(event==0) {
2265                                                 insertkey(id, ID_CA, NULL, NULL, CAM_LENS);
2266                                         }
2267                                         else if(event==1) {
2268                                                 insertkey(id, ID_CA, NULL, NULL, CAM_STA);
2269                                                 insertkey(id, ID_CA, NULL, NULL, CAM_END);
2270                                         }
2271                                         else if(event==2) {
2272                                                 insertkey(id, ID_CA, NULL, NULL, CAM_YF_APERT);
2273                                         }
2274                                         else if(event==3) {
2275                                                 insertkey(id, ID_CA, NULL, NULL, CAM_YF_FDIST);
2276                                         }
2277                                 }
2278                         }
2279                 }
2280                 else if(FALSE /* && G.buts->mainb==BUTS_SOUND */) {
2281                         if(G.ssound) {
2282                                 id= G.buts->lockpoin;
2283                                 if(id) {
2284                                         event= pupmenu("Insert Key %t|Volume%x0|Pitch%x1|Panning%x2|Attennuation%x3");
2285                                         if(event== -1) return;
2286
2287                                         if(event==0) {
2288                                                 insertkey(id, ID_SO, NULL, NULL, SND_VOLUME);
2289                                         }
2290                                         if(event==1) {
2291                                                 insertkey(id, ID_SO, NULL, NULL, SND_PITCH);
2292                                         }
2293                                         if(event==2) {
2294                                                 insertkey(id, ID_SO, NULL, NULL, SND_PANNING);
2295                                         }
2296                                         if(event==3) {
2297                                                 insertkey(id, ID_SO, NULL, NULL, SND_ATTEN);
2298                                         }
2299                                 }
2300                         }
2301                 }
2302                 
2303                 BIF_undo_push("Insert Key Buttons");
2304
2305                 allqueue(REDRAWACTION, 0);
2306                 allqueue(REDRAWNLA, 0);
2307                 allqueue(REDRAWIPO, 0);
2308                 allspace(REMAKEIPO, 0);
2309
2310         }
2311         else if(curarea->spacetype==SPACE_VIEW3D) {
2312                 ob= OBACT;
2313
2314                 if (ob && (ob->flag & OB_POSEMODE)) {
2315                         strcpy(menustr, "Insert Key%t|Loc%x0|Rot%x1|Size%x2|LocRot%x3|LocRotSize%x4|Avail%x9");
2316                 }
2317                 else {
2318                         base= FIRSTBASE;
2319                         while(base) {
2320                                 if TESTBASELIB(base) break;
2321                                 base= base->next;
2322                         }
2323                         if(base==NULL) return;
2324                 
2325                         strcpy(menustr, "Insert Key%t|Loc%x0|Rot%x1|Size%x2|LocRot%x3|LocRotSize%x4|Layer%x5|Avail%x9");
2326                 }
2327                 
2328                 if(ob) {
2329                         if(ob->type==OB_MESH) strcat(menustr, "| %x6|Mesh%x7");
2330                         else if(ob->type==OB_LATTICE) strcat(menustr, "| %x6|Lattice%x7");
2331                         else if(ob->type==OB_CURVE) strcat(menustr, "| %x6|Curve%x7");
2332                         else if(ob->type==OB_SURF) strcat(menustr, "| %x6|Surface%x7");
2333                         if(ob->flag & OB_FROMGROUP)     strcat(menustr, "| %x6|Entire Group%x10");
2334                 }
2335                 
2336                 event= pupmenu(menustr);
2337                 if(event== -1) return;
2338                 
2339                 if(event==7) { // ob != NULL
2340                         insert_shapekey(ob);
2341                         return;
2342                 }
2343                 
2344                 if(event==10) {
2345                         Group *group= find_group(ob);
2346                         if(group) {
2347                                 add_group_key(group);
2348                                 allqueue(REDRAWBUTSOBJECT, 0);
2349                         }
2350                 }
2351                 
2352                 if (ob && (ob->flag & OB_POSEMODE)){
2353                         bPoseChannel *pchan;
2354
2355                         if (ob->action && ob->action->id.lib) {
2356                                 error ("Can't key libactions");
2357                                 return;
2358                         }
2359                         
2360                         set_pose_keys(ob);  // sets pchan->flag to POSE_KEY if bone selected
2361                         id= &ob->id;
2362                         for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
2363                                 if (pchan->flag & POSE_KEY){
2364                                         if(event==0 || event==3 ||event==4) {
2365                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X);
2366                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y);
2367                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z);
2368                                         }
2369                                         if(event==1 || event==3 ||event==4) {
2370                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
2371                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
2372                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
2373                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
2374                                         }
2375                                         if(event==2 || event==4) {
2376                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X);
2377                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y);
2378                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z);
2379                                         }
2380                                         if (event==9 && ob->action) {
2381                                                 bActionChannel *achan;
2382                                                 
2383                                                 for (achan = ob->action->chanbase.first; achan; achan=achan->next){
2384                                                         if (achan->ipo && !strcmp (achan->name, pchan->name)){
2385                                                                 for (icu = achan->ipo->curve.first; icu; icu=icu->next){
2386                                                                         insertkey(id, ID_PO, achan->name, NULL, icu->adrcode);
2387                                                                 }
2388                                                                 break;
2389                                                         }
2390                                                 }
2391                                         }
2392                                 }
2393                         }
2394                         remake_action_ipos(ob->action);
2395
2396                         allqueue(REDRAWIPO, 0);
2397                         allqueue(REDRAWACTION, 0);
2398                         allqueue(REDRAWNLA, 0);
2399                 }
2400                 else {
2401                         base= FIRSTBASE;
2402                         while(base) {
2403                                 if TESTBASELIB(base) {
2404                                         char *actname= NULL;
2405                                         
2406                                         id= (ID *)(base->object);
2407                                         
2408                                         if(ob->ipoflag & OB_ACTION_OB)
2409                                                 actname= "Object";
2410                                         
2411                                         /* all curves in ipo deselect */
2412                                         if(base->object->ipo) {
2413                                                 icu= base->object->ipo->curve.first;
2414                                                 while(icu) {
2415                                                         icu->flag &= ~IPO_SELECT;
2416                                                         if(event==9) insertkey(id, ID_OB, actname, NULL, icu->adrcode);
2417                                                         icu= icu->next;
2418                                                 }
2419                                         }
2420                                         
2421                                         if(event==0 || event==3 ||event==4) {
2422                                                 insertkey(id, ID_OB, actname, NULL, OB_LOC_X);
2423                                                 insertkey(id, ID_OB, actname, NULL, OB_LOC_Y);
2424                                                 insertkey(id, ID_OB, actname, NULL, OB_LOC_Z);
2425                                         }
2426                                         if(event==1 || event==3 ||event==4) {
2427                                                 insertkey(id, ID_OB, actname, NULL, OB_ROT_X);
2428                                                 insertkey(id, ID_OB, actname, NULL, OB_ROT_Y);
2429                                                 insertkey(id, ID_OB, actname, NULL, OB_ROT_Z);
2430                                         }
2431                                         if(event==2 || event==4) {
2432                                                 insertkey(id, ID_OB, actname, NULL, OB_SIZE_X);
2433                                                 insertkey(id, ID_OB, actname, NULL, OB_SIZE_Y);
2434                                                 insertkey(id, ID_OB, actname, NULL, OB_SIZE_Z);
2435                                         }
2436                                         if(event==5) {
2437                                                 /* remove localview  */
2438                                                 tlay= base->object->lay;
2439                                                 base->object->lay &= 0xFFFFFF;
2440                                                 insertkey(id, ID_OB, actname, NULL, OB_LAY);
2441                                                 base->object->lay= tlay;
2442                                         }
2443                                 }
2444                                 base= base->next;
2445                         }
2446                 }
2447
2448                 if(event==0) BIF_undo_push("Insert Loc Key");
2449                 else if(event==1) BIF_undo_push("Insert Rot Key");
2450                 else if(event==2) BIF_undo_push("Insert Size Key");
2451                 else if(event==3) BIF_undo_push("Insert LocRot Key");
2452                 else if(event==4) BIF_undo_push("Insert LocRotSize Key");
2453                 else if(event==5) BIF_undo_push("Insert Layer Key");
2454                 else if(event==7) BIF_undo_push("Insert Vertex Key");
2455                 else if(event==9) BIF_undo_push("Insert Avail Key");
2456
2457                 allspace(REMAKEIPO, 0);
2458                 allqueue(REDRAWIPO, 0);
2459                 allqueue(REDRAWVIEW3D, 0);
2460                 allqueue(REDRAWACTION, 0);
2461                 allqueue(REDRAWNLA, 0);
2462         }
2463         
2464 }
2465
2466 /* ****************************************************************************** */
2467
2468 void add_duplicate_editipo(void)
2469 {
2470         Object *ob;
2471         EditIpo *ei;
2472         IpoCurve *icu;
2473         BezTriple *bezt, *beztn, *newb;
2474         int tot, a, b;
2475         
2476         get_status_editipo();
2477         if(totipo_vertsel==0) return;
2478         
2479         ei= G.sipo->editipo;
2480         for(a=0; a<G.sipo->totipo; a++, ei++) {
2481                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2482                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2483                                 icu= ei->icu;
2484                                 
2485                                 /* how many points */
2486                                 tot= 0;
2487                                 b= icu->totvert;
2488                                 bezt= icu->bezt;
2489                                 while(b--) {
2490                                         if(bezt->f2 & 1) tot++;
2491                                         bezt++;
2492                                 }
2493                                 
2494                                 if(tot) {
2495                                         icu->totvert+= tot;
2496                                         newb= beztn= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2497                                         bezt= icu->bezt;
2498                                         b= icu->totvert-tot;
2499                                         while(b--) {
2500                                                 *beztn= *bezt;
2501                                                 if(bezt->f2 & 1) {
2502                                                         beztn->f1= beztn->f2= beztn->f3= 0;
2503                                                         beztn++;
2504                                                         *beztn= *bezt;
2505                                                 }
2506                                                 beztn++;
2507                                                 bezt++;
2508                                         }
2509                                         MEM_freeN(icu->bezt);
2510                                         icu->bezt= newb;
2511                                         
2512                                         calchandles_ipocurve(icu);
2513                                 }
2514                         }
2515                 }
2516         }
2517         
2518         if(G.sipo->showkey) {
2519                 make_ipokey();
2520                 if(G.sipo->blocktype==ID_OB) {
2521                         ob= OBACT;
2522                         if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
2523                 }
2524         }
2525         BIF_undo_push("Duplicate Ipo");
2526         transform_ipo('g');
2527 }
2528
2529 void remove_doubles_ipo(void)
2530 {
2531         EditIpo *ei;
2532         IpoKey *ik, *ikn;
2533         BezTriple *bezt, *newb, *new1;
2534         float val;
2535         int mode, a, b;
2536         
2537         ei= G.sipo->editipo;
2538         for(a=0; a<G.sipo->totipo; a++, ei++) {
2539                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2540                         
2541                         /* OR the curve is selected OR in editmode OR in keymode */
2542                         mode= 0;
2543                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) mode= 1;
2544                         else if(ei->flag & IPO_SELECT) mode= 2;
2545                         
2546                         if(mode) {
2547                                 bezt= ei->icu->bezt;
2548                                 newb= new1= MEM_mallocN(ei->icu->totvert*sizeof(BezTriple), "newbezt");
2549                                 *newb= *bezt;
2550                                 b= ei->icu->totvert-1;
2551                                 bezt++;
2552                                 while(b--) {
2553                                         
2554                                         /* can we remove? */
2555                                         if(mode==2 || (bezt->f2 & 1)) {
2556                                         
2557                                                 /* are the points different? */
2558                                                 if( fabs( bezt->vec[1][0]-newb->vec[1][0] ) > 0.9 ) {
2559                                                         newb++;
2560                                                         *newb= *bezt;
2561                                                 }
2562                                                 else {
2563                                                         /* median */
2564                                                         VecMidf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2565                                                         VecMidf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2566                                                         VecMidf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2567                                                         
2568                                                         newb->h1= newb->h2= HD_FREE;
2569                                                         
2570                                                         ei->icu->totvert--;
2571                                                 }
2572                                                 
2573                                         }
2574                                         else {
2575                                                 newb++;
2576                                                 *newb= *bezt;
2577                                         }
2578                                         bezt++;
2579                                 }
2580                                 
2581                                 MEM_freeN(ei->icu->bezt);
2582                                 ei->icu->bezt= new1;
2583                                 
2584                                 calchandles_ipocurve(ei->icu);                          
2585                         }
2586                 }
2587         }
2588         
2589         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2590
2591         /* remove double keys */
2592         if(G.sipo->showkey) {
2593                 ik= G.sipo->ipokey.first;
2594                 ikn= ik->next;
2595                 
2596                 while(ik && ikn) {
2597                         if( (ik->flag & 1) && (ikn->flag & 1) ) {
2598                                 if( fabs(ik->val-ikn->val) < 0.9 ) {
2599                                         val= (float)((ik->val + ikn->val)/2.0);
2600                                         
2601                                         for(a=0; a<G.sipo->totipo; a++) {
2602                                                 if(ik->data[a]) ik->data[a]->vec[1][0]= val;
2603                                                 if(ikn->data[a]) ikn->data[a]->vec[1][0]= val;                                          
2604                                         }
2605                                 }
2606                         }
2607                         ik= ikn;
2608                         ikn= ikn->next;
2609
2610                 }
2611                 
2612                 editipo_changed(G.sipo, 1);     /* makes ipokeys agian! */
2613
2614         }
2615         deselectall_editipo();
2616 }
2617
2618 void join_ipo_menu(void)
2619 {
2620         int mode = 0;
2621         mode= pupmenu("Join %t|All Selected %x1|Selected Doubles %x2");
2622         
2623         if (mode == -1) return;
2624         
2625         join_ipo(mode);
2626 }
2627
2628 void join_ipo(int mode)
2629 {
2630         EditIpo *ei;
2631         IpoKey *ik;
2632         IpoCurve *icu;
2633         BezTriple *bezt, *beztn, *newb;
2634         float val;
2635         int tot, a, b;
2636         
2637         get_status_editipo();
2638         
2639         /* Mode events:
2640          * All Selected: 1
2641          * Selected Doubles: 2
2642          */
2643         
2644         if( mode==2 ) {
2645                 remove_doubles_ipo();
2646                 return;
2647         }
2648         
2649         /* first: multiple selected verts in 1 curve */
2650         ei= G.sipo->editipo;
2651         for(a=0; a<G.sipo->totipo; a++, ei++) {
2652                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2653                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2654                                 icu= ei->icu;
2655                                 
2656                                 /* how many points */
2657                                 tot= 0;
2658                                 b= icu->totvert;
2659                                 bezt= icu->bezt;
2660                                 while(b--) {
2661                                         if(bezt->f2 & 1) tot++;
2662                                         bezt++;
2663                                 }
2664                                 
2665                                 if(tot>1) {
2666                                         tot--;
2667                                         icu->totvert-= tot;
2668                                         
2669                                         newb= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2670                                         /* the first point is the new one */
2671                                         beztn= newb+1;
2672                                         tot= 0;
2673                                         
2674                                         bezt= icu->bezt;
2675                                         b= icu->totvert+tot+1;
2676                                         while(b--) {
2677                                                 
2678                                                 if(bezt->f2 & 1) {
2679                                                         if(tot==0) *newb= *bezt;
2680                                                         else {
2681                                                                 VecAddf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2682                                                                 VecAddf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2683                                                                 VecAddf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2684                                                         }
2685                                                         tot++;
2686                                                 }
2687                                                 else {
2688                                                         *beztn= *bezt;
2689                                                         beztn++;
2690                                                 }
2691                                                 bezt++;
2692                                         }
2693                                         
2694                                         VecMulf(newb->vec[0], (float)(1.0/((float)tot)));
2695                                         VecMulf(newb->vec[1], (float)(1.0/((float)tot)));
2696                                         VecMulf(newb->vec[2], (float)(1.0/((float)tot)));
2697                                         
2698                                         MEM_freeN(icu->bezt);
2699                                         icu->bezt= newb;
2700                                         
2701                                         sort_time_ipocurve(icu);
2702                                         calchandles_ipocurve(icu);
2703                                 }
2704                         }
2705                 }
2706         }
2707         
2708         /* next: in keymode: join multiple selected keys */
2709         
2710         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2711         
2712         if(G.sipo->showkey) {
2713                 ik= G.sipo->ipokey.first;
2714                 val= 0.0;
2715                 tot= 0;
2716                 while(ik) {
2717                         if(ik->flag & 1) {
2718                                 for(a=0; a<G.sipo->totipo; a++) {
2719                                         if(ik->data[a]) {
2720                                                 val+= ik->data[a]->vec[1][0];
2721                                                 break;
2722                                         }
2723                                 }
2724                                 tot++;
2725                         }
2726                         ik= ik->next;
2727                 }
2728                 if(tot>1) {
2729                         val/= (float)tot;
2730                         
2731                         ik= G.sipo->ipokey.first;
2732                         while(ik) {
2733                                 if(ik->flag & 1) {
2734                                         for(a=0; a<G.sipo->totipo; a++) {
2735                                                 if(ik->data[a]) {
2736                                                         ik->data[a]->vec[1][0]= val;
2737                                                 }
2738                                         }
2739                                 }
2740                                 ik= ik->next;
2741                         }
2742                         editipo_changed(G.sipo, 0);
2743                 }
2744         }
2745         deselectall_editipo();
2746         BIF_undo_push("Join Ipo");
2747 }
2748
2749 void ipo_snap_menu(void)
2750 {
2751         short event;
2752         
2753         event= pupmenu("Snap %t|Horizontal %x1|To Next %x2|To Frame %x3|To Current Frame%x4");
2754         if(event < 1) return;
2755
2756         ipo_snap(event);
2757 }
2758
2759 void ipo_snap(short event)
2760 {
2761         EditIpo *ei;
2762         BezTriple *bezt;
2763         float dx = 0.0;
2764         int a, b;
2765         short ok, ok2;
2766         
2767         /* events:
2768          * Horizontal : 1
2769          * To Next: 2
2770          * To Frame: 3
2771          * To Current Frame: 4
2772          */
2773          
2774         get_status_editipo();
2775
2776         ei= G.sipo->editipo;
2777         for(b=0; b<G.sipo->totipo; b++, ei++) {
2778                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2779                 
2780                         ok2= 0;
2781                         if(G.sipo->showkey) ok2= 1;
2782                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok2= 2;
2783                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok2= 3;
2784                         
2785                         if(ok2) {
2786                                 bezt= ei->icu->bezt;
2787                                 a= ei->icu->totvert;
2788                                 while(a--) {
2789                                         ok= 0;
2790                                         if(totipo_vert) {
2791                                                  if(bezt->f2 & 1) ok= 1;
2792                                         }
2793                                         else ok= 1;
2794                                         
2795                                         if(ok) {
2796                                                 if(event==1) {
2797                                                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
2798                                                         if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2799                                                         if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2800                                                 }
2801                                                 else if(event==2) {
2802                                                         if(a) {
2803                                                                 bezt->vec[0][1]= bezt->vec[1][1]= bezt->vec[2][1]= (bezt+1)->vec[1][1];
2804                                                                 if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2805                                                                 if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2806                                                         }
2807                                                 }
2808                                                 else if(event==3) {
2809                                                         bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
2810                                                 }
2811                                                 else if(event==4) {     /* to current frame */
2812                                                         
2813                                                         if(ok2==1 || ok2==2) {
2814                                                                 
2815                                                                 if(G.sipo->blocktype==ID_SEQ) {
2816                                                                         Sequence *seq;
2817                                                         
2818                                                                         seq= (Sequence *)G.sipo->from;
2819                                                                         if(seq) {
2820                                                                                 dx= (float)(CFRA-seq->startdisp);
2821                                                                                 dx= (float)(100.0*dx/((float)(seq->enddisp-seq->startdisp)));
2822                                                                                 
2823                                                                                 dx-= bezt->vec[1][0];
2824                                                                         }
2825                                                                 }
2826                                                                 else dx= G.scene->r.framelen*CFRA - bezt->vec[1][0];
2827                                                                 
2828                                                                 bezt->vec[0][0]+= dx;
2829                                                                 bezt->vec[1][0]+= dx;
2830                                                                 bezt->vec[2][0]+= dx;
2831                                                         }
2832                                                 }
2833                                         }
2834                                         
2835                                         bezt++;
2836                                 }
2837                                 calchandles_ipocurve(ei->icu);
2838                         }
2839                 }
2840         }
2841         editipo_changed(G.sipo, 1);
2842         BIF_undo_push("Snap Ipo");
2843 }
2844
2845 /*
2846  * When deleting an IPO curve from Python, check if the Ipo is being
2847  * edited and if so clear the pointer to the old curve.
2848  */
2849
2850 void del_ipoCurve ( IpoCurve * icu )
2851 {
2852         int i;
2853         EditIpo *ei= G.sipo->editipo;
2854         if (!ei) return;
2855
2856         for(i=0; i<G.sipo->totipo; i++, ei++) {
2857                 if ( ei->icu == icu ) {
2858                         ei->flag &= ~(IPO_SELECT | IPO_EDIT);
2859                         ei->icu= NULL;
2860                         return;
2861                 }
2862         }
2863 }
2864
2865 void del_ipo(void)
2866 {
2867         EditIpo *ei;
2868         BezTriple *bezt, *bezt1;
2869         int a, b;
2870         int del, event;
2871
2872         get_status_editipo();
2873         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
2874         
2875         if(totipo_edit==0 && totipo_sel==0 && totipo_vertsel==0) {
2876                 if(okee("Erase selected keys"))
2877                    delete_key(OBACT);
2878                 return;
2879         }
2880         
2881         if( okee("Erase selected")==0 ) return;
2882
2883         // first round, can we delete entire parts? 
2884         ei= G.sipo->editipo;
2885         for(a=0; a<G.sipo->totipo; a++, ei++) {
2886         
2887                 del= 0;
2888                 
2889                 if(G.sipo->showkey==0 && totipo_edit==0) {
2890                         if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
2891                                 del= 1;
2892                         }
2893                 }
2894                 else {
2895                         if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
2896                                 if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2897                                         if(ei->icu->bezt) {
2898                                                 bezt= ei->icu->bezt;
2899                                                 b= ei->icu->totvert;
2900                                                 if(b) {
2901                                                         while(b) {
2902                                                                 if( BEZSELECTED(bezt) );
2903                                                                 else break;
2904                                                                 b--;
2905                                                                 bezt++;
2906                                                         }
2907                                                         if(b==0) del= 1;
2908                                                 }
2909                                         }
2910                                 }
2911                         }