c29b98b376877d87b08d84802bb5ee5c731fa36d
[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
895 /* evaluates context in the current UI */
896 /* blocktype is type of ipo */
897 /* from is the base pointer to find data to change (ob in case of action or pose) */
898 static void get_ipo_context(short blocktype, ID **from, Ipo **ipo, char *actname, char *constname)
899 {
900         Object *ob= OBACT;
901         
902         *from= NULL;
903         *ipo= NULL;
904         
905         if(blocktype==ID_CO) {
906                 if (ob) {
907                         bConstraintChannel *chan;
908                         bConstraint *con= get_active_constraint(ob);
909                         
910                         if(con) {
911                                 BLI_strncpy(constname, con->name, 32);
912                                 
913                                 chan= get_active_constraint_channel(ob);
914                                 if(chan) {
915                                         *ipo= chan->ipo;
916                                         BLI_strncpy(constname, con->name, 32);
917                                 }
918                                 
919                                 *from= &ob->id;
920                                 
921                                 /* set actname if in posemode */
922                                 if(ob->action) {
923                                         if(ob->flag & OB_POSEMODE) {
924                                                 bPoseChannel *pchan= get_active_posechannel(ob);
925                                                 if(pchan)
926                                                         BLI_strncpy(actname, pchan->name, 32);
927                                         }
928                                         else if(ob->ipoflag & OB_ACTION_OB)
929                                                 strcpy(actname, "Object");
930                                 }
931                         }
932                 }
933         }
934         else if(blocktype==ID_PO) {
935                 if (ob && ob->action && ob->type==OB_ARMATURE) {
936                         bPoseChannel *pchan= get_active_posechannel(ob);
937                         
938                         *from= (ID *)ob;
939                         if (pchan) {
940                                 bActionChannel *achan;
941                                 
942                                 BLI_strncpy(actname, pchan->name, 32);  /* also set when no channel yet */
943                                 
944                                 achan= get_action_channel(ob->action, pchan->name);
945                                 if(achan)
946                                         *ipo= achan->ipo;
947                         }
948                 } 
949                 
950         }
951         else if(blocktype==ID_OB) {
952                 if(ob) {
953                         *from= (ID *)ob;
954                         if(ob->ipoflag & OB_ACTION_OB) {
955                                 if (ob->action) {
956                                         bActionChannel *achan= get_action_channel(ob->action, "Object");
957                                         if(achan) {
958                                                 *ipo= achan->ipo;
959                                                 BLI_strncpy(actname, achan->name, 32);
960                                         }
961                                 }
962                         }
963                         else {
964                                 *ipo= ob->ipo;
965                         }
966                 }
967         }
968         else if(blocktype==ID_SEQ) {
969                 extern Sequence *last_seq;
970                 
971                 *from= (ID *)last_seq;
972                 if(last_seq) *ipo= last_seq->ipo;
973         }
974         else if(blocktype==ID_WO) {
975                 World *wo= G.scene->world;
976                 *from= (ID *)wo;
977                 if(wo) *ipo= wo->ipo;
978         }
979         else if(blocktype==ID_TE) {
980                 if(ob) {
981                         Tex *tex= give_current_texture(ob, ob->actcol);
982                         *from= (ID *)tex;
983                         if(tex) *ipo= tex->ipo;
984                 }
985         }
986         else if(blocktype==ID_MA) {
987                 if(ob) {
988                         Material *ma= give_current_material(ob, ob->actcol);
989                         *from= (ID *)ma;
990                         if(ma) *ipo= ma->ipo;
991                 }
992         }
993         else if(blocktype==ID_KE) {
994                 if(ob) {
995                         Key *key= ob_get_key(ob);
996                         *from= (ID *)key;
997                         if(key) *ipo= key->ipo;
998                 }
999         }
1000         else if(blocktype==ID_CU) {
1001                 if(ob && ob->type==OB_CURVE) {
1002                         Curve *cu= ob->data;
1003                         *from= (ID *)cu;
1004                         *ipo= cu->ipo;
1005                 }
1006         }
1007         else if(blocktype==ID_LA) {
1008                 if(ob && ob->type==OB_LAMP) {
1009                         Lamp *la= ob->data;
1010                         *from= (ID *)la;
1011                         *ipo= la->ipo;
1012                 }
1013         }
1014         else if(blocktype==ID_CA) {
1015                 if(ob && ob->type==OB_CAMERA) {
1016                         Camera *ca= ob->data;
1017                         *from= (ID *)ca;
1018                         if(ca) *ipo= ca->ipo;
1019                 }
1020         }
1021         else if(blocktype==ID_SO) {
1022                 
1023                 //              if (G.buts && G.buts->mainb == BUTS_SOUND) {
1024                 //                      bSound *sound = G.buts->lockpoin;
1025                 //                      *from= (ID *)sound;
1026                 //                      if(sound) *ipo= sound->ipo;
1027                 //              }
1028         }
1029 }
1030
1031 /* called on each redraw, check if editipo data has to be remade */
1032 void test_editipo(void)
1033 {
1034         int doit= 0;
1035         
1036         if(G.sipo->pin==0) {
1037                 Ipo *ipo;
1038                 ID *from;
1039                 char actname[32]="", constname[32]="";
1040                 
1041                 get_ipo_context(G.sipo->blocktype, &from, &ipo, actname, constname);
1042                 
1043                 if(G.sipo->ipo != ipo) {
1044                         G.sipo->ipo= ipo;
1045                         if(ipo) G.v2d->cur= ipo->cur;
1046                         doit= 1;
1047                 }
1048                 if(G.sipo->from != from) {
1049                         G.sipo->from= from;
1050                         doit= 1;
1051                 }
1052                 if( strcmp(G.sipo->actname, actname)) {
1053                         BLI_strncpy(G.sipo->actname, actname, 32);
1054                         doit= 1;
1055                 }
1056                 if( strcmp(G.sipo->constname, constname)) {
1057                         BLI_strncpy(G.sipo->constname, constname, 32);
1058                         doit= 1;
1059                 }
1060                 
1061                 if(G.sipo->ipo)
1062                         G.sipo->ipo->cur = G.v2d->cur;
1063                 
1064         }
1065                 
1066         if(G.sipo->editipo==NULL || doit) {
1067                 make_editipo();
1068         }
1069 }
1070
1071 /* ****************** EditIpo ************************ */
1072
1073 int totipo_edit, totipo_sel, totipo_curve, totipo_vis, totipo_vert, totipo_vertsel, totipo_key, totipo_keysel;
1074
1075 void get_status_editipo(void)
1076 {
1077         EditIpo *ei;
1078         IpoKey *ik;
1079         BezTriple *bezt;
1080         int a, b;
1081         
1082         totipo_vis= 0;
1083         totipo_curve= 0;
1084         totipo_sel= 0;
1085         totipo_edit= 0;
1086         totipo_vert= 0;
1087         totipo_vertsel= 0;
1088         totipo_key= 0;
1089         totipo_keysel= 0;
1090         
1091         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1092         
1093         ei= G.sipo->editipo;
1094         if(ei==0) return;
1095         for(a=0; a<G.sipo->totipo; a++) {
1096                 if( ei->flag & IPO_VISIBLE ) {
1097                         totipo_vis++;
1098                         if(ei->flag & IPO_SELECT) totipo_sel++;
1099                         if(ei->icu && ei->icu->totvert) totipo_curve++;
1100                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
1101                                 
1102                                 /* if showkey: do count the vertices (for grab) */
1103                                 if(G.sipo->showkey==0) totipo_edit++;
1104                                 
1105                                 if(ei->icu) {
1106                                         if(ei->icu->bezt) {
1107                                                 bezt= ei->icu->bezt;
1108                                                 b= ei->icu->totvert;
1109                                                 while(b--) {
1110                                                         if(ei->icu->ipo==IPO_BEZ) {
1111                                                                 if(bezt->f1 & 1) totipo_vertsel++;
1112                                                                 if(bezt->f3 & 1) totipo_vertsel++;
1113                                                                 totipo_vert+= 2;
1114                                                         }
1115                                                         if(bezt->f2 & 1) totipo_vertsel++;
1116                                                         
1117                                                         totipo_vert++;
1118                                                         bezt++;
1119                                                 }
1120                                         }
1121                                 }
1122                         }
1123                 }
1124                 ei++;
1125         }
1126         
1127         if(G.sipo->showkey) {
1128                 ik= G.sipo->ipokey.first;
1129                 while(ik) {
1130                         totipo_key++;
1131                         if(ik->flag & 1) totipo_keysel++;
1132                         ik= ik->next;
1133                 }
1134         }
1135 }
1136
1137 /* synchronize editipo flag with icu flag and ipokey flags */
1138 void update_editipo_flags(void)
1139 {
1140         EditIpo *ei;
1141         IpoKey *ik;
1142         int a;
1143         
1144         ei= G.sipo->editipo;
1145         if(ei) {
1146                 for(a=0; a<G.sipo->totipo; a++, ei++) {
1147                         if(ei->icu) ei->icu->flag= ei->flag;
1148                 }
1149         }
1150         if(G.sipo->showkey) {
1151                 ik= G.sipo->ipokey.first;
1152                 while(ik) {
1153                         for(a=0; a<G.sipo->totipo; a++) {
1154                                 if(ik->data[a]) {
1155                                         if(ik->flag & 1) {
1156                                                 ik->data[a]->f1 |= 1;
1157                                                 ik->data[a]->f2 |= 1;
1158                                                 ik->data[a]->f3 |= 1;
1159                                         }
1160                                         else {
1161                                                 ik->data[a]->f1 &= ~1;
1162                                                 ik->data[a]->f2 &= ~1;
1163                                                 ik->data[a]->f3 &= ~1;
1164                                         }
1165                                 }
1166                         }
1167                         ik= ik->next;
1168                 }
1169         }
1170 }
1171
1172 /* sort of enter/leave editmode for curves */
1173 void set_editflag_editipo(void)
1174 {
1175         EditIpo *ei;
1176         int a; /*  , tot= 0, ok= 0; */
1177         
1178         /* after showkey immediately go to editing of selected points */
1179         if(G.sipo->showkey) {
1180                 G.sipo->showkey= 0;
1181                 if(G.sipo->ipo) G.sipo->ipo->showkey= 0;
1182                 ei= G.sipo->editipo;
1183                 for(a=0; a<G.sipo->totipo; a++, ei++) ei->flag |= IPO_SELECT;
1184                 scrarea_queue_headredraw(curarea);
1185                 allqueue(REDRAWVIEW3D, 0);
1186         }
1187         
1188         get_status_editipo();
1189         
1190         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1191         
1192         ei= G.sipo->editipo;
1193         for(a=0; a<G.sipo->totipo; a++, ei++) {         
1194                 if(ei->icu) {
1195                         if(ei->flag & IPO_VISIBLE) {
1196                                 
1197                                 if(totipo_edit==0 && (ei->flag & IPO_SELECT)) {
1198                                         ei->flag |= IPO_EDIT;
1199                                         ei->icu->flag= ei->flag;
1200                                 }
1201                                 else if(totipo_edit && (ei->flag & IPO_EDIT)) {
1202                                         ei->flag -= IPO_EDIT;
1203                                         ei->icu->flag= ei->flag;
1204                                 }
1205                                 else if(totipo_vis==1) {
1206                                         if(ei->flag & IPO_EDIT) ei->flag -= IPO_EDIT;
1207                                         else ei->flag |= IPO_EDIT;
1208                                         ei->icu->flag= ei->flag;
1209                                 }
1210                         }
1211                 }
1212         }
1213         scrarea_queue_headredraw(curarea);
1214         scrarea_queue_winredraw(curarea);
1215 }
1216
1217 static short findnearest_ipovert(IpoCurve **icu, BezTriple **bezt)
1218 {
1219         /* selected verts get a disadvantage */
1220         /* in icu and (bezt or bp) the nearest is written */
1221         /* return 0 1 2: handlepunt */
1222         EditIpo *ei;
1223         BezTriple *bezt1;
1224         int dist= 100, temp, a, b;
1225         short mval[2], hpoint=0;
1226
1227         *icu= 0;
1228         *bezt= 0;
1229
1230         getmouseco_areawin(mval);
1231
1232         ei= G.sipo->editipo;
1233         for(a=0; a<G.sipo->totipo; a++, ei++) {
1234                 if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu)) {
1235                         
1236                         if(ei->icu->bezt) {
1237                                 bezt1= ei->icu->bezt;
1238                                 b= ei->icu->totvert;
1239                                 while(b--) {
1240
1241                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[0], bezt1->s[0]);
1242                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[1], bezt1->s[1]);
1243                                         ipoco_to_areaco_noclip(G.v2d, bezt1->vec[2], bezt1->s[2]);
1244                                                                                 
1245                                         if(ei->disptype==IPO_DISPBITS) {
1246                                                 temp= abs(mval[0]- bezt1->s[1][0]);
1247                                         }
1248                                         else temp= abs(mval[0]- bezt1->s[1][0])+ abs(mval[1]- bezt1->s[1][1]);
1249
1250                                         if( bezt1->f2 & 1) temp+=5;
1251                                         if(temp<dist) { 
1252                                                 hpoint= 1; 
1253                                                 *bezt= bezt1; 
1254                                                 dist= temp; 
1255                                                 *icu= ei->icu; 
1256                                         }
1257                                         
1258                                         if(ei->disptype!=IPO_DISPBITS && ei->icu->ipo==IPO_BEZ) {
1259                                                 /* middle points get an advantage */
1260                                                 temp= -3+abs(mval[0]- bezt1->s[0][0])+ abs(mval[1]- bezt1->s[0][1]);
1261                                                 if( bezt1->f1 & 1) temp+=5;
1262                                                 if(temp<dist) { 
1263                                                         hpoint= 0; 
1264                                                         *bezt= bezt1; 
1265                                                         dist= temp; 
1266                                                         *icu= ei->icu; 
1267                                                 }
1268                 
1269                                                 temp= abs(mval[0]- bezt1->s[2][0])+ abs(mval[1]- bezt1->s[2][1]);
1270                                                 if( bezt1->f3 & 1) temp+=5;
1271                                                 if(temp<dist) { 
1272                                                         hpoint= 2; 
1273                                                         *bezt=bezt1; 
1274                                                         dist= temp; 
1275                                                         *icu= ei->icu; 
1276                                                 }
1277                                         }
1278                                         bezt1++;
1279                                 }
1280                         }
1281                 }
1282         }
1283
1284         return hpoint;
1285 }
1286
1287 void mouse_select_ipo(void)
1288 {
1289         Object *ob;
1290         Key *key;
1291         KeyBlock *kb, *actkb=NULL, *curkb;
1292         EditIpo *ei, *actei= 0;
1293         IpoCurve *icu;
1294         IpoKey *ik, *actik;
1295         BezTriple *bezt;
1296         float x, y, dist, mindist;
1297         int a, oldflag = 0, hand, ok;
1298         short mval[2], xo, yo;
1299         
1300         if(G.sipo->editipo==0) return;
1301         
1302         get_status_editipo();
1303         
1304         if(G.sipo->showkey) {
1305                 getmouseco_areawin(mval);
1306                 
1307                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1308                 actik= 0;
1309                 mindist= 1000.0;
1310                 ik= G.sipo->ipokey.first;
1311                 while(ik) {
1312                         dist= (float)(fabs(ik->val-x));
1313                         if(ik->flag & 1) dist+= 1.0;
1314                         if(dist < mindist) {
1315                                 actik= ik;
1316                                 mindist= dist;
1317                         }
1318                         ik= ik->next;
1319                 }
1320                 if(actik) {
1321                         oldflag= actik->flag;
1322                         
1323                         if(G.qual & LR_SHIFTKEY);
1324                         else deselectall_editipo();
1325                         
1326                         if(G.qual & LR_SHIFTKEY) {
1327                                 if(oldflag & 1) actik->flag &= ~1;
1328                                 else actik->flag |= 1;
1329                         }
1330                         else {
1331                                 actik->flag |= 1;
1332                         }
1333                 }
1334         }
1335         else if(totipo_edit) {
1336                 
1337                 hand= findnearest_ipovert(&icu, &bezt);
1338                 
1339                 if(G.qual & LR_SHIFTKEY) {
1340                         if(bezt) {
1341                                 if(hand==1) {
1342                                         if(BEZSELECTED(bezt)) {
1343                                                 bezt->f1= bezt->f2= bezt->f3= 0;
1344                                         }
1345                                         else {
1346                                                 bezt->f1= bezt->f2= bezt->f3= 1;
1347                                         }
1348                                 }
1349                                 else if(hand==0) {
1350                                         if(bezt->f1 & 1) bezt->f1= 0;
1351                                         else bezt->f1= 1;
1352                                 }
1353                                 else {
1354                                         if(bezt->f3 & 1) bezt->f3= 0;
1355                                         else bezt->f3= 1;
1356                                 }
1357                         }                               
1358                 }
1359                 else {
1360                         deselectall_editipo();
1361                         
1362                         if(bezt) {
1363                                 if(hand==1) {
1364                                         bezt->f1|= 1; bezt->f2|= 1; bezt->f3|= 1;
1365                                 }
1366                                 else if(hand==0) bezt->f1|= 1;
1367                                 else bezt->f3|= 1;
1368                         }
1369                 }
1370         }
1371         else {
1372                 
1373                 /* vertex keys ? */
1374                 if(G.sipo->blocktype==ID_KE && G.sipo->from) {
1375                         int i, index= 1;
1376                         
1377                         key= (Key *)G.sipo->from;
1378                         ob= OBACT;
1379                         curkb= BLI_findlink(&key->block, ob->shapenr-1);
1380                         
1381                         ei= G.sipo->editipo;
1382                         if(key->type==KEY_NORMAL || (ei->flag & IPO_VISIBLE)) {
1383                                 getmouseco_areawin(mval);
1384                                 
1385                                 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1386                                 /* how much is 20 pixels? */
1387                                 mindist= (float)(20.0*(G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)curarea->winy);
1388                                 
1389                                 for(i=1, kb= key->block.first; kb; kb= kb->next, i++) {
1390                                         dist= (float)(fabs(kb->pos-y));
1391                                         if(kb==curkb) dist+= (float)0.01;
1392                                         if(dist < mindist) {
1393                                                 actkb= kb;
1394                                                 mindist= dist;
1395                                                 index= i;
1396                                         }
1397                                 }
1398                                 if(actkb) {
1399                                         ok= TRUE;
1400                                         if(G.obedit && actkb!=curkb) {
1401                                                 ok= okee("Copy key after leaving Edit Mode");
1402                                         }
1403                                         if(ok) {
1404                                                 /* also does all keypos */
1405                                                 deselectall_editipo();
1406                                                 set_active_key(index);
1407                                                 set_active_editipo(ei+index-1);
1408                                         }
1409                                 }
1410                         }
1411                 }
1412                 
1413                 /* select curve */
1414                 if(actkb==NULL) {
1415                         if(totipo_vis==1) {
1416                                 ei= G.sipo->editipo;
1417                                 for(a=0; a<G.sipo->totipo; a++, ei++) {
1418                                         if(ei->icu) {
1419                                                 if(ei->flag & IPO_VISIBLE) actei= ei;
1420                                         }
1421                                 }
1422                         }
1423                         else if(totipo_vis>1) {
1424                                 actei= select_proj_ipo(0, 0);
1425                         }
1426                         
1427                         if(actei) oldflag= actei->flag;
1428                         
1429                         if(G.qual & LR_SHIFTKEY);
1430                         else deselectall_editipo();
1431                         
1432                         if(actei) {
1433                                 if(G.qual & LR_SHIFTKEY) {
1434                                         if(oldflag & IPO_SELECT) actei->flag &= ~IPO_SELECT;
1435                                         else actei->flag |= IPO_SELECT;
1436                                 }
1437                                 else {
1438                                         actei->flag |= IPO_SELECT;
1439                                 }
1440                                 set_active_editipo(actei);
1441                         }
1442                 }
1443         }
1444         
1445         update_editipo_flags();
1446         
1447         force_draw(0);
1448         BIF_undo_push("Select Ipo");
1449         
1450         if(G.sipo->showkey && G.sipo->blocktype==ID_OB) {
1451                 ob= OBACT;
1452                 if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
1453         }
1454         
1455         getmouseco_areawin(mval);
1456         xo= mval[0]; 
1457         yo= mval[1];
1458         
1459         while(get_mbut()&R_MOUSE) {             
1460                 getmouseco_areawin(mval);
1461                 if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
1462                         
1463                         if(actkb) move_keys(OBACT);
1464                         else transform_ipo('g');
1465                         
1466                         return;
1467                 }
1468                 BIF_wait_for_statechange();
1469         }
1470 }
1471
1472
1473 /* *********************************** */
1474
1475 /* handling of right-hand channel/curve buttons in ipo window */
1476 void do_ipowin_buts(short event)
1477 {
1478         EditIpo *ei = NULL;
1479         int a;
1480
1481         /* without shift, all other channels are made invisible */
1482         if((G.qual & LR_SHIFTKEY)==0) {
1483                 if(event>G.sipo->totipo) return;
1484                 ei = G.sipo->editipo;
1485                 for(a=0; a<G.sipo->totipo; a++) {
1486                         if(a!=event) ei->flag &= ~IPO_VISIBLE;
1487                         else ei->flag |= IPO_VISIBLE;
1488                         ei++;
1489                 }
1490         }
1491         
1492         /* set active */
1493         if(event>=0 && event<G.sipo->totipo) {
1494                 ei= G.sipo->editipo;    // void pointer...
1495                 set_active_editipo(ei+event);
1496                 set_active_key(event+1);        // only if there's a key, of course
1497         }
1498         scrarea_queue_winredraw(curarea);
1499         
1500         update_editipo_flags();
1501         get_status_editipo();
1502
1503         if(G.sipo->showkey) {
1504                 make_ipokey();
1505                 if(G.sipo->blocktype==ID_OB) allqueue(REDRAWVIEW3D, 0);
1506         }
1507
1508 }
1509
1510 /* the fake buttons to the left of channel names, for select/deselect curves */
1511 void do_ipo_selectbuttons(void)
1512 {
1513         EditIpo *ei, *ei1;
1514         int a, nr;
1515         short mval[2];
1516         
1517         if(G.sipo->showkey) return;
1518         
1519         /* do not allow editipo here: convert editipos to selected */
1520         get_status_editipo();
1521         if(totipo_edit) {
1522                 set_editflag_editipo();
1523         }
1524         
1525         /* which */
1526         getmouseco_areawin(mval);
1527
1528         nr= -(mval[1]-curarea->winy+30-G.sipo->butofs-IPOBUTY)/IPOBUTY;
1529         if(nr>=0 && nr<G.sipo->totipo) {
1530                 ei= G.sipo->editipo;
1531                 ei+= nr;
1532                 
1533                 set_active_editipo(ei);
1534                 set_active_key(nr+1);
1535
1536                 if(ei->icu) {
1537                         if((ei->flag & IPO_VISIBLE)==0) {
1538                                 ei->flag |= IPO_VISIBLE|IPO_SELECT;
1539                         }
1540         
1541                         if((G.qual & LR_SHIFTKEY)==0) {
1542                                 ei1= G.sipo->editipo;
1543                                 for(a=0; a<G.sipo->totipo; a++) {
1544                                         ei1->flag &= ~IPO_SELECT;
1545                                         ei1++;
1546                                 }
1547                         }
1548
1549                         if(ei->flag & IPO_SELECT) {
1550                                 ei->flag &= ~IPO_SELECT;
1551                         }
1552                         else {
1553                                 ei->flag |= IPO_SELECT;
1554                         }
1555                         
1556                         update_editipo_flags();
1557                         scrarea_queue_winredraw(curarea);
1558                 }
1559         }
1560         BIF_undo_push("Select Ipo curve");
1561 }
1562
1563 /* ********************************* Inserting keys ********************************************* */
1564
1565 /* depending type, it returns ipo, if neded it creates one */
1566 /* returns either action ipo or "real" ipo */
1567 /* arguments define full context;
1568    - *from has to be set always, to Object in case of Actions
1569    - blocktype defines available channels of Ipo struct (blocktype ID_OB can be in action too)
1570    - if actname, use this to locate action, and optional constname to find the channel 
1571 */
1572
1573 /* note; check header_ipo.c, spaceipo_assign_ipo() too */
1574 Ipo *verify_ipo(ID *from, short blocktype, char *actname, char *constname)
1575 {
1576
1577         if(from==NULL || from->lib) return NULL;
1578         
1579         /* first check action ipos */
1580         if(actname && actname[0]) {
1581                 Object *ob= (Object *)from;
1582                 bActionChannel *achan;
1583                 
1584                 if(ob->action==NULL)
1585                         ob->action= add_empty_action(blocktype);
1586                 
1587                 achan= verify_action_channel(ob->action, actname);
1588                 
1589                 if(achan) {
1590                         /* constraint exception */
1591                         if(blocktype==ID_CO) {
1592                                 bConstraintChannel *conchan= verify_constraint_channel(&achan->constraintChannels, constname);
1593                                 if(conchan->ipo==NULL) {
1594                                         conchan->ipo= add_ipo("CoIpo", ID_CO);  
1595                                 }
1596                                 return conchan->ipo;
1597                         }
1598                         else {
1599                                 if(achan->ipo==NULL) {
1600                                         achan->ipo= add_ipo("ActIpo", blocktype);
1601                                 }
1602                                 
1603                                 return achan->ipo;
1604                         }
1605                 }
1606         }
1607         else {
1608                 
1609                 switch(GS(from->name)) {
1610                 case ID_OB:
1611                         {
1612                                 Object *ob= (Object *)from;
1613                                 /* constraint exception */
1614                                 if(blocktype==ID_CO) {
1615                                         bConstraintChannel *conchan= verify_constraint_channel(&ob->constraintChannels, constname);
1616                                         if(conchan->ipo==NULL) {
1617                                                 conchan->ipo= add_ipo("CoIpo", ID_CO);  
1618                                         }
1619                                         return conchan->ipo;
1620                                 }
1621                                 else if(blocktype==ID_OB) {
1622                                         if(ob->ipo==NULL) {
1623                                                 ob->ipo= add_ipo("ObIpo", ID_OB);
1624                                         }
1625                                         return ob->ipo;
1626                                 }
1627                         }
1628                         break;
1629                 case ID_MA:
1630                         {
1631                                 Material *ma= (Material *)from;
1632
1633                                 if(ma->ipo==NULL) {
1634                                         ma->ipo= add_ipo("MatIpo", ID_MA);
1635                                 }
1636                                 return ma->ipo;
1637                         }
1638                         break;
1639                 case ID_TE:
1640                         {
1641                                 Tex *tex= (Tex *)from;
1642
1643                                 if(tex->ipo==NULL) {
1644                                         tex->ipo= add_ipo("TexIpo", ID_TE);
1645                                 }
1646                                 return tex->ipo;
1647                         }
1648                         break;
1649                 case ID_SEQ:
1650                         {
1651                                 Sequence *seq= (Sequence *)from;        /* note, sequence is mimicing Id */
1652
1653                                 if((seq->type & SEQ_EFFECT)||(seq->type == SEQ_SOUND)) {
1654                                         if(seq->ipo==NULL) {
1655                                                 seq->ipo= add_ipo("SeqIpo", ID_SEQ);
1656                                         }
1657                                         return seq->ipo;
1658                                 }
1659                         }
1660                         break;
1661                 case ID_CU:
1662                         {
1663                                 Curve *cu= (Curve *)from;
1664                                 
1665                                 if(cu->ipo==NULL) {
1666                                         cu->ipo= add_ipo("CuIpo", ID_CU);
1667                                 }
1668                                 return cu->ipo;
1669                         }
1670                         break;
1671                 case ID_KE:
1672                         {
1673                                 Key *key= (Key *)from;
1674
1675                                 if(key->ipo==NULL) {
1676                                         key->ipo= add_ipo("KeyIpo", ID_KE);
1677                                 }
1678                                 return key->ipo;
1679                         }
1680                         break;
1681                 case ID_WO:
1682                         {
1683                                 World *wo= (World *)from;
1684
1685                                 if(wo->ipo==NULL) {
1686                                         wo->ipo= add_ipo("WoIpo", ID_WO);
1687                                 }
1688                                 return wo->ipo;
1689                         }
1690                         break;
1691                 case ID_LA:
1692                         {
1693                                 Lamp *la= (Lamp *)from;
1694                                 
1695                                 if(la->ipo==NULL) {
1696                                         la->ipo= add_ipo("LaIpo", ID_LA);
1697                                 }
1698                                 return la->ipo;
1699                         }
1700                         break;
1701                 case ID_CA:
1702                         {
1703                                 Camera *ca= (Camera *)from;
1704
1705                                 if(ca->ipo==NULL) {
1706                                         ca->ipo= add_ipo("CaIpo", ID_CA);
1707                                 }
1708                                 return ca->ipo;
1709                         }
1710                         break;
1711                 case ID_SO:
1712                         {
1713                                 bSound *snd= (bSound *)from;
1714
1715                                 if(snd->ipo==NULL) {
1716                                         snd->ipo= add_ipo("SndIpo", ID_SO);
1717                                 }
1718                                 return snd->ipo;
1719                         }
1720                 }
1721         }
1722         
1723         return NULL;    
1724 }
1725
1726 /* returns and creates */
1727 IpoCurve *verify_ipocurve(ID *from, short blocktype, char *actname, char *constname, int adrcode)
1728 {
1729         Ipo *ipo;
1730         IpoCurve *icu= NULL;
1731         
1732         /* return 0 if lib */
1733         /* creates ipo too */
1734         ipo= verify_ipo(from, blocktype, actname, constname);
1735         
1736         if(ipo && ipo->id.lib==NULL) {
1737                 
1738                 for(icu= ipo->curve.first; icu; icu= icu->next) {
1739                         if(icu->adrcode==adrcode) break;
1740                 }
1741                 if(icu==NULL) {
1742                         icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
1743
1744                         icu->flag |= IPO_VISIBLE|IPO_AUTO_HORIZ;
1745                         icu->blocktype= blocktype;
1746                         icu->adrcode= adrcode;
1747                         
1748                         set_icu_vars(icu);
1749                         
1750                         BLI_addtail( &(ipo->curve), icu);
1751                 }
1752         }
1753
1754         return icu;
1755 }
1756
1757 void insert_vert_ipo(IpoCurve *icu, float x, float y)
1758 {
1759         BezTriple *bezt, beztr, *newbezt;
1760         int a = 0, h1, h2;
1761         
1762         memset(&beztr, 0, sizeof(BezTriple));
1763         beztr.vec[0][0]= x; // set all three points, for nicer start position
1764         beztr.vec[0][1]= y;
1765         beztr.vec[1][0]= x;
1766         beztr.vec[1][1]= y;
1767         beztr.vec[2][0]= x;
1768         beztr.vec[2][1]= y;
1769         beztr.hide= IPO_BEZ;
1770         beztr.f1= beztr.f2= beztr.f3= SELECT;
1771         beztr.h1= beztr.h2= HD_AUTO;
1772                 
1773         bezt= icu->bezt;
1774                 
1775         if(bezt==NULL) {
1776                 icu->bezt= MEM_callocN( sizeof(BezTriple), "beztriple");
1777                 *(icu->bezt)= beztr;
1778                 icu->totvert= 1;
1779         }
1780         else {
1781                 /* all vertices deselect */
1782                 for(a=0; a<icu->totvert; a++, bezt++) {
1783                         bezt->f1= bezt->f2= bezt->f3= 0;
1784                 }
1785         
1786                 bezt= icu->bezt;
1787                 for(a=0; a<=icu->totvert; a++, bezt++) {
1788                         
1789                         /* no double points */
1790                         if(a<icu->totvert && (bezt->vec[1][0]>x-IPOTHRESH && bezt->vec[1][0]<x+IPOTHRESH)) {
1791                                 *(bezt)= beztr;
1792                                 break;
1793                         }
1794                         if(a==icu->totvert || bezt->vec[1][0] > x) {
1795                                 newbezt= MEM_callocN( (icu->totvert+1)*sizeof(BezTriple), "beztriple");
1796                                 
1797                                 if(a>0) memcpy(newbezt, icu->bezt, a*sizeof(BezTriple));
1798                                 
1799                                 bezt= newbezt+a;
1800                                 *(bezt)= beztr;
1801                                 
1802                                 if(a<icu->totvert) memcpy(newbezt+a+1, icu->bezt+a, (icu->totvert-a)*sizeof(BezTriple));
1803                                 
1804                                 MEM_freeN(icu->bezt);
1805                                 icu->bezt= newbezt;
1806                                 
1807                                 icu->totvert++;
1808                                 break;
1809                         }
1810                 }
1811         }
1812         
1813         
1814         calchandles_ipocurve(icu);
1815         
1816         /* set handletype */
1817         if(icu->totvert>2) {
1818                 h1= h2= HD_AUTO;
1819                 if(a>0) h1= (bezt-1)->h2;
1820                 if(a<icu->totvert-1) h2= (bezt+1)->h1;
1821                 bezt->h1= h1;
1822                 bezt->h2= h2;
1823
1824                 calchandles_ipocurve(icu);
1825         }
1826 }
1827
1828 void add_vert_ipo(void)
1829 {
1830         EditIpo *ei;
1831         float x, y;
1832         int val;
1833         short mval[2];
1834
1835         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
1836         if(G.sipo->showkey) {
1837                 G.sipo->showkey= 0;
1838                 free_ipokey(&G.sipo->ipokey);
1839         }
1840         
1841         getmouseco_areawin(mval);
1842         
1843         if(mval[0]>G.v2d->mask.xmax) return;
1844         
1845         ei= get_active_editipo();
1846         if(ei==0) {
1847                 error("No active Ipo curve");
1848                 return;
1849         }
1850         
1851         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1852         
1853         if(ei->icu==NULL) {
1854                 if(G.sipo->from) {
1855                         ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei->adrcode);
1856                         ei->flag |= ei->icu->flag & IPO_AUTO_HORIZ;     /* new curve could have been added, weak... */
1857                 }
1858         }
1859         if(ei->icu==NULL) return;
1860
1861         if(ei->disptype==IPO_DISPBITS) {
1862                 ei->icu->vartype= IPO_BITS;
1863                 val= (int)floor(y-0.5);
1864                 if(val<0) val= 0;
1865                 y= (float)(1 << val);
1866         }
1867         
1868         insert_vert_ipo(ei->icu, x, y);
1869
1870         /* to be sure: if icu was 0, or only 1 curve visible */
1871         ei->flag |= IPO_SELECT;
1872         ei->icu->flag= ei->flag;
1873         
1874         editipo_changed(G.sipo, 1);
1875         BIF_undo_push("Add Ipo vertex");
1876 }
1877
1878 static void *get_context_ipo_poin(ID *id, int blocktype, char *actname, IpoCurve *icu, int *vartype)
1879 {
1880         if(blocktype==ID_PO) {
1881                 if(GS(id->name)==ID_OB) {
1882                         Object *ob= (Object *)id;
1883                         bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
1884                         
1885                         *vartype= IPO_FLOAT;
1886                         return get_pchan_ipo_poin(pchan, icu->adrcode);
1887                 }
1888                 return NULL;
1889         }
1890         else
1891                 return get_ipo_poin(id, icu, vartype);
1892
1893 }
1894
1895 void insertkey(ID *id, int blocktype, char *actname, char *constname, int adrcode)
1896 {
1897         IpoCurve *icu;
1898         Object *ob;
1899         void *poin= NULL;
1900         float curval, cfra;
1901         int vartype;
1902         
1903         icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
1904         
1905         if(icu) {
1906                 
1907                 poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
1908                 
1909                 if(poin) {
1910                         curval= read_ipo_poin(poin, vartype);
1911                         
1912                         cfra= frame_to_float(CFRA);
1913                         
1914                         /* if action is mapped in NLA, it returns a correction */
1915                         if(actname && actname[0] && GS(id->name)==ID_OB)
1916                                 cfra= get_action_frame((Object *)id, cfra);
1917                         
1918                         if( GS(id->name)==ID_OB ) {
1919                                 ob= (Object *)id;
1920                                 if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
1921                                         /* actually frametofloat calc again! */
1922                                         cfra-= ob->sf*G.scene->r.framelen;
1923                                 }
1924                         }
1925                         
1926                         insert_vert_ipo(icu, cfra, curval);
1927                 }
1928         }
1929 }
1930
1931 void insertkey_editipo(void)
1932 {
1933         EditIpo *ei;
1934         IpoKey *ik;
1935         ID *id;
1936         float *fp, cfra, *insertvals;
1937         int a, nr, ok, tot;
1938         short event;
1939         
1940         ei= get_active_editipo();
1941         if(ei && ei->icu && ei->icu->driver) 
1942                 event= pupmenu("Insert Curve %t|Default one-to-one mapping %x3");
1943         else if(G.sipo->showkey)
1944                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1|Selected Keys %x2");
1945         else 
1946                 event= pupmenu("Insert Key Vertices %t|Current Frame %x1");
1947         
1948         if(event<1) return;
1949         
1950         if(event==3) {
1951                 IpoDriver *driver= ei->icu->driver;
1952                 
1953                 if(ei->icu->bezt) MEM_freeN(ei->icu->bezt);
1954                 ei->icu->totvert= 0;
1955                 ei->icu->bezt= NULL;
1956                 
1957                 insert_vert_ipo(ei->icu, 0.0f, 0.0f);
1958                 
1959                 if(ELEM3(driver->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
1960                         if(ei->disptype==IPO_DISPDEGR)
1961                                 insert_vert_ipo(ei->icu, 18.0f, 18.0f);
1962                         else
1963                                 insert_vert_ipo(ei->icu, 18.0f, 1.0f);
1964                 }
1965                 else
1966                         insert_vert_ipo(ei->icu, 1.0f, 1.0f);
1967                 
1968                 ei->flag |= IPO_SELECT|IPO_VISIBLE;
1969                 ei->icu->flag= ei->flag;
1970                 ei->icu->extrap= IPO_DIR;
1971
1972                 do_ipo_buttons(B_IPOHOME);
1973         }
1974         else {
1975                 ei= G.sipo->editipo;
1976                 for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
1977                         if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
1978                         
1979                                 ok= 0;
1980                                 if(G.sipo->showkey) ok= 1;
1981                                 else if(ei->flag & IPO_SELECT) ok= 1;
1982
1983                                 if(ok) {
1984                                         /* count amount */
1985                                         if(event==1) tot= 1;
1986                                         else {
1987                                                 ik= G.sipo->ipokey.first;
1988                                                 tot= 0;
1989                                                 while(ik) {
1990                                                         if(ik->flag & 1) tot++;
1991                                                         ik= ik->next;
1992                                                 }
1993                                         }
1994                                         if(tot) {
1995                                         
1996                                                 /* correction for ob timeoffs */
1997                                                 cfra= frame_to_float(CFRA);
1998                                                 id= G.sipo->from;       
1999                                                 if(id && GS(id->name)==ID_OB ) {
2000                                                         Object *ob= (Object *)id;
2001                                                         if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
2002                                                                 cfra-= ob->sf*G.scene->r.framelen;
2003                                                         }
2004                                                 }
2005                                                 else if(id && GS(id->name)==ID_SEQ) {
2006                                                         extern Sequence *last_seq;      /* editsequence.c */
2007                                                         
2008                                                         if(last_seq) {
2009                                                                 cfra= (float)(100.0*(cfra-last_seq->startdisp)/((float)(last_seq->enddisp-last_seq->startdisp)));
2010                                                         }
2011                                                 }
2012                                 
2013                                                 insertvals= MEM_mallocN(sizeof(float)*2*tot, "insertkey_editipo");
2014                                                 /* make sure icu->curval is correct */
2015                                                 calc_ipo(G.sipo->ipo, cfra);
2016                                                 
2017                                                 if(event==1) {
2018                                                         insertvals[0]= cfra;
2019                                                         
2020                                                         insertvals[1]= ei->icu->curval;
2021                                                 }
2022                                                 else {
2023                                                         fp= insertvals;
2024                                                         ik= G.sipo->ipokey.first;
2025                                                         while(ik) {
2026                                                                 if(ik->flag & 1) {
2027                                                                         calc_ipo(G.sipo->ipo, ik->val);
2028
2029                                                                         fp[0]= ik->val;
2030                                                                         fp[1]= ei->icu->curval;
2031                                                                         fp+= 2;
2032                                                                 }
2033                                                                 ik= ik->next;
2034                                                         }
2035                                                 }
2036                                                 fp= insertvals;
2037                                                 for(a=0; a<tot; a++, fp+=2) {
2038                                                         insert_vert_ipo(ei->icu, fp[0], fp[1]);
2039                                                 }
2040                                                 
2041                                                 MEM_freeN(insertvals);
2042                                                 calc_ipo(G.sipo->ipo, (float)CFRA);
2043                                         }
2044                                 }
2045                         }
2046                 }
2047         }
2048         BIF_undo_push("Insert Key Ipo");
2049         allqueue (REDRAWACTION, 0);
2050         allqueue(REDRAWNLA, 0);
2051         allqueue(REDRAWIPO, 0);
2052         allspace(REMAKEIPO, 0);
2053 }
2054
2055
2056 void common_insertkey(void)
2057 {
2058         Base *base;
2059         Object *ob;
2060         Material *ma;
2061         ID *id;
2062         IpoCurve *icu;
2063         World *wo;
2064         Lamp *la;
2065         int tlay, map, event;
2066         char menustr[256];
2067         
2068         if(curarea->spacetype==SPACE_IPO) {
2069                 insertkey_editipo();
2070         }
2071         else if(curarea->spacetype==SPACE_BUTS) {
2072                 if(G.buts->mainb==CONTEXT_SHADING) {
2073                         int tab= G.buts->tab[CONTEXT_SHADING];
2074                         
2075                         if(tab==TAB_SHADING_MAT) {
2076                                 id= G.buts->lockpoin;
2077                                 ma= G.buts->lockpoin;
2078                                 if(id) {
2079                                         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");
2080                                         if(event== -1) return;
2081                                         
2082                                         map= texchannel_to_adrcode(ma->texact);
2083                                         
2084                                         if(event==0 || event==10) {
2085                                                 insertkey(id, ID_MA, NULL, NULL, MA_COL_R);
2086                                                 insertkey(id, ID_MA, NULL, NULL, MA_COL_G);
2087                                                 insertkey(id, ID_MA, NULL, NULL, MA_COL_B);
2088                                         }
2089                                         if(event==1 || event==10) {
2090                                                 insertkey(id, ID_MA, NULL, NULL, MA_ALPHA);
2091                                         }
2092                                         if(event==2 || event==10) {
2093                                                 insertkey(id, ID_MA, NULL, NULL, MA_HASIZE);
2094                                         }
2095                                         if(event==3 || event==10) {
2096                                                 insertkey(id, ID_MA, NULL, NULL, MA_MODE);
2097                                         }
2098                                         if(event==10) {
2099                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC_R);
2100                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC_G);
2101                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC_B);
2102                                                 insertkey(id, ID_MA, NULL, NULL, MA_REF);
2103                                                 insertkey(id, ID_MA, NULL, NULL, MA_EMIT);
2104                                                 insertkey(id, ID_MA, NULL, NULL, MA_AMB);
2105                                                 insertkey(id, ID_MA, NULL, NULL, MA_SPEC);
2106                                                 insertkey(id, ID_MA, NULL, NULL, MA_HARD);
2107                                                 insertkey(id, ID_MA, NULL, NULL, MA_MODE);
2108                                                 insertkey(id, ID_MA, NULL, NULL, MA_TRANSLU);
2109                                                 insertkey(id, ID_MA, NULL, NULL, MA_ADD);
2110                                         }
2111                                         if(event==14) {
2112                                                 insertkey(id, ID_MA, NULL, NULL, MA_RAYM);
2113                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESMIR);
2114                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESMIRI);
2115                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESTRA);
2116                                                 insertkey(id, ID_MA, NULL, NULL, MA_FRESTRAI);
2117                                         }
2118                                         if(event==12 || event==11) {
2119                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_X);
2120                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_Y);
2121                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_Z);
2122                                         }
2123                                         if(event==13 || event==11) {
2124                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_X);
2125                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_Y);
2126                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_Z);
2127                                         }
2128                                         if(event==11) {
2129                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_R);
2130                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_G);
2131                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_B);
2132                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_DVAR);
2133                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_COLF);
2134                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_NORF);
2135                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_VARF);
2136                                                 insertkey(id, ID_MA, NULL, NULL, map+MAP_DISP);
2137                                         }
2138                                 }
2139                         }
2140                         else if(tab==TAB_SHADING_WORLD) {
2141                                 id= G.buts->lockpoin;
2142                                 wo= G.buts->lockpoin;
2143                                 if(id) {
2144                                         event= pupmenu("Insert Key %t|Zenith RGB%x0|Horizon RGB%x1|Mist%x2|Stars %x3|Offset%x12|Size%x13");
2145                                         if(event== -1) return;
2146                                         
2147                                         map= texchannel_to_adrcode(wo->texact);
2148                                         
2149                                         if(event==0) {
2150                                                 insertkey(id, ID_WO, NULL, NULL, WO_ZEN_R);
2151                                                 insertkey(id, ID_WO, NULL, NULL, WO_ZEN_G);
2152                                                 insertkey(id, ID_WO, NULL, NULL, WO_ZEN_B);
2153                                         }
2154                                         if(event==1) {
2155                                                 insertkey(id, ID_WO, NULL, NULL, WO_HOR_R);
2156                                                 insertkey(id, ID_WO, NULL, NULL, WO_HOR_G);
2157                                                 insertkey(id, ID_WO, NULL, NULL, WO_HOR_B);
2158                                         }
2159                                         if(event==2) {
2160                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISI);
2161                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISTDI);
2162                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISTSTA);
2163                                                 insertkey(id, ID_WO, NULL, NULL, WO_MISTHI);
2164                                         }
2165                                         if(event==3) {
2166                                                 insertkey(id, ID_WO, NULL, NULL, WO_STAR_R);
2167                                                 insertkey(id, ID_WO, NULL, NULL, WO_STAR_G);
2168                                                 insertkey(id, ID_WO, NULL, NULL, WO_STAR_B);
2169                                                 insertkey(id, ID_WO, NULL, NULL, WO_STARDIST);
2170                                                 insertkey(id, ID_WO, NULL, NULL, WO_STARSIZE);
2171                                         }
2172                                         if(event==12) {
2173                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_X);
2174                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_Y);
2175                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_Z);
2176                                         }
2177                                         if(event==13) {
2178                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_X);
2179                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_Y);
2180                                                 insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_Z);
2181                                         }
2182                                 }
2183                         }
2184                         else if(tab==TAB_SHADING_LAMP) {
2185                                 id= G.buts->lockpoin;
2186                                 la= G.buts->lockpoin;
2187                                 if(id) {
2188                                         event= pupmenu("Insert Key %t|RGB%x0|Energy%x1|Spot Size%x2|Offset%x12|Size%x13");
2189                                         if(event== -1) return;
2190                                         
2191                                         map= texchannel_to_adrcode(la->texact);
2192                                         
2193                                         if(event==0) {
2194                                                 insertkey(id, ID_LA, NULL, NULL, LA_COL_R);
2195                                                 insertkey(id, ID_LA, NULL, NULL, LA_COL_G);
2196                                                 insertkey(id, ID_LA, NULL, NULL, LA_COL_B);
2197                                         }
2198                                         if(event==1) {
2199                                                 insertkey(id, ID_LA, NULL, NULL, LA_ENERGY);
2200                                         }
2201                                         if(event==2) {
2202                                                 insertkey(id, ID_LA, NULL, NULL, LA_SPOTSI);
2203                                         }
2204                                         if(event==12) {
2205                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_X);
2206                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_Y);
2207                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_Z);
2208                                         }
2209                                         if(event==13) {
2210                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_X);
2211                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_Y);
2212                                                 insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_Z);
2213                                         }
2214
2215                                 }
2216                         }
2217                 }
2218                 else if(G.buts->mainb==CONTEXT_OBJECT) {
2219                         ob= OBACT;
2220                         if(ob && ob->type==OB_MESH) {
2221                                 id= (ID *) (ob);
2222                                 if(id) {
2223                                         event= pupmenu("Insert Key %t|Surface Damping%x0|Random Damping%x1|Permeability%x2|Force Strength%x3|Force Falloff%x4");
2224                                         if(event== -1) return;
2225
2226                                         if(event==0) {
2227                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_SDAMP);
2228                                         }
2229                                         if(event==1) {
2230                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_RDAMP);
2231                                         }
2232                                         if(event==2) {
2233                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_PERM);
2234                                         }
2235                                         if(event==3) {
2236                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_FSTR);
2237                                         }
2238                                         if(event==4) {
2239                                                 insertkey(id, ID_OB, NULL, NULL, OB_PD_FFALL);
2240                                         }
2241
2242                                 }
2243                         }
2244                 }
2245                 else if(G.buts->mainb==CONTEXT_EDITING) {
2246                         ob= OBACT;
2247                         if(ob && ob->type==OB_CAMERA) {
2248                                 id= G.buts->lockpoin;
2249                                 if(id) {
2250                                         /* yafray: insert key extended with aperture and focal distance */
2251                                         if (G.scene->r.renderer==R_INTERN)
2252                                                 event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1");
2253                                         else
2254                                                 event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1|Aperture%x2|FocalDistance%x3");
2255                                         if(event== -1) return;
2256
2257                                         if(event==0) {
2258                                                 insertkey(id, ID_CA, NULL, NULL, CAM_LENS);
2259                                         }
2260                                         else if(event==1) {
2261                                                 insertkey(id, ID_CA, NULL, NULL, CAM_STA);
2262                                                 insertkey(id, ID_CA, NULL, NULL, CAM_END);
2263                                         }
2264                                         else if(event==2) {
2265                                                 insertkey(id, ID_CA, NULL, NULL, CAM_YF_APERT);
2266                                         }
2267                                         else if(event==3) {
2268                                                 insertkey(id, ID_CA, NULL, NULL, CAM_YF_FDIST);
2269                                         }
2270                                 }
2271                         }
2272                 }
2273                 else if(FALSE /* && G.buts->mainb==BUTS_SOUND */) {
2274                         if(G.ssound) {
2275                                 id= G.buts->lockpoin;
2276                                 if(id) {
2277                                         event= pupmenu("Insert Key %t|Volume%x0|Pitch%x1|Panning%x2|Attennuation%x3");
2278                                         if(event== -1) return;
2279
2280                                         if(event==0) {
2281                                                 insertkey(id, ID_SO, NULL, NULL, SND_VOLUME);
2282                                         }
2283                                         if(event==1) {
2284                                                 insertkey(id, ID_SO, NULL, NULL, SND_PITCH);
2285                                         }
2286                                         if(event==2) {
2287                                                 insertkey(id, ID_SO, NULL, NULL, SND_PANNING);
2288                                         }
2289                                         if(event==3) {
2290                                                 insertkey(id, ID_SO, NULL, NULL, SND_ATTEN);
2291                                         }
2292                                 }
2293                         }
2294                 }
2295                 
2296                 BIF_undo_push("Insert Key Buttons");
2297
2298                 allqueue(REDRAWACTION, 0);
2299                 allqueue(REDRAWNLA, 0);
2300                 allqueue(REDRAWIPO, 0);
2301                 allspace(REMAKEIPO, 0);
2302
2303         }
2304         else if(curarea->spacetype==SPACE_VIEW3D) {
2305                 ob= OBACT;
2306
2307                 if (ob && (ob->flag & OB_POSEMODE)) {
2308                         strcpy(menustr, "Insert Key%t|Loc%x0|Rot%x1|Size%x2|LocRot%x3|LocRotSize%x4|Avail%x9");
2309                 }
2310                 else {
2311                         base= FIRSTBASE;
2312                         while(base) {
2313                                 if TESTBASELIB(base) break;
2314                                 base= base->next;
2315                         }
2316                         if(base==NULL) return;
2317                 
2318                         strcpy(menustr, "Insert Key%t|Loc%x0|Rot%x1|Size%x2|LocRot%x3|LocRotSize%x4|Layer%x5|Avail%x9");
2319                 }
2320                 
2321                 if(ob) {
2322                         if(ob->type==OB_MESH) strcat(menustr, "| %x6|Mesh%x7");
2323                         else if(ob->type==OB_LATTICE) strcat(menustr, "| %x6|Lattice%x7");
2324                         else if(ob->type==OB_CURVE) strcat(menustr, "| %x6|Curve%x7");
2325                         else if(ob->type==OB_SURF) strcat(menustr, "| %x6|Surface%x7");
2326                         if(ob->flag & OB_FROMGROUP)     strcat(menustr, "| %x6|Entire Group%x10");
2327                 }
2328                 
2329                 event= pupmenu(menustr);
2330                 if(event== -1) return;
2331                 
2332                 if(event==7) { // ob != NULL
2333                         insert_shapekey(ob);
2334                         return;
2335                 }
2336                 
2337                 if(event==10) {
2338                         Group *group= find_group(ob);
2339                         if(group) {
2340                                 add_group_key(group);
2341                                 allqueue(REDRAWBUTSOBJECT, 0);
2342                         }
2343                 }
2344                 
2345                 if (ob && (ob->flag & OB_POSEMODE)){
2346                         bPoseChannel *pchan;
2347
2348                         if (ob->action && ob->action->id.lib) {
2349                                 error ("Can't key libactions");
2350                                 return;
2351                         }
2352                         
2353                         set_pose_keys(ob);  // sets pchan->flag to POSE_KEY if bone selected
2354                         id= &ob->id;
2355                         for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
2356                                 if (pchan->flag & POSE_KEY){
2357                                         if(event==0 || event==3 ||event==4) {
2358                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X);
2359                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y);
2360                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z);
2361                                         }
2362                                         if(event==1 || event==3 ||event==4) {
2363                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
2364                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
2365                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
2366                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
2367                                         }
2368                                         if(event==2 || event==4) {
2369                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X);
2370                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y);
2371                                                 insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z);
2372                                         }
2373                                         if (event==9 && ob->action) {
2374                                                 bActionChannel *achan;
2375                                                 
2376                                                 for (achan = ob->action->chanbase.first; achan; achan=achan->next){
2377                                                         if (achan->ipo && !strcmp (achan->name, pchan->name)){
2378                                                                 for (icu = achan->ipo->curve.first; icu; icu=icu->next){
2379                                                                         insertkey(id, ID_PO, achan->name, NULL, icu->adrcode);
2380                                                                 }
2381                                                                 break;
2382                                                         }
2383                                                 }
2384                                         }
2385                                 }
2386                         }
2387                         remake_action_ipos(ob->action);
2388
2389                         DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
2390
2391                         allqueue(REDRAWIPO, 0);
2392                         allqueue(REDRAWACTION, 0);
2393                         allqueue(REDRAWNLA, 0);
2394                 }
2395                 else {
2396                         base= FIRSTBASE;
2397                         while(base) {
2398                                 if TESTBASELIB(base) {
2399                                         char *actname= NULL;
2400                                         
2401                                         id= (ID *)(base->object);
2402                                         
2403                                         if(ob->ipoflag & OB_ACTION_OB)
2404                                                 actname= "Object";
2405                                         
2406                                         /* all curves in ipo deselect */
2407                                         if(base->object->ipo) {
2408                                                 icu= base->object->ipo->curve.first;
2409                                                 while(icu) {
2410                                                         icu->flag &= ~IPO_SELECT;
2411                                                         if(event==9) insertkey(id, ID_OB, actname, NULL, icu->adrcode);
2412                                                         icu= icu->next;
2413                                                 }
2414                                         }
2415                                         
2416                                         if(event==0 || event==3 ||event==4) {
2417                                                 insertkey(id, ID_OB, actname, NULL, OB_LOC_X);
2418                                                 insertkey(id, ID_OB, actname, NULL, OB_LOC_Y);
2419                                                 insertkey(id, ID_OB, actname, NULL, OB_LOC_Z);
2420                                         }
2421                                         if(event==1 || event==3 ||event==4) {
2422                                                 insertkey(id, ID_OB, actname, NULL, OB_ROT_X);
2423                                                 insertkey(id, ID_OB, actname, NULL, OB_ROT_Y);
2424                                                 insertkey(id, ID_OB, actname, NULL, OB_ROT_Z);
2425                                         }
2426                                         if(event==2 || event==4) {
2427                                                 insertkey(id, ID_OB, actname, NULL, OB_SIZE_X);
2428                                                 insertkey(id, ID_OB, actname, NULL, OB_SIZE_Y);
2429                                                 insertkey(id, ID_OB, actname, NULL, OB_SIZE_Z);
2430                                         }
2431                                         if(event==5) {
2432                                                 /* remove localview  */
2433                                                 tlay= base->object->lay;
2434                                                 base->object->lay &= 0xFFFFFF;
2435                                                 insertkey(id, ID_OB, actname, NULL, OB_LAY);
2436                                                 base->object->lay= tlay;
2437                                         }
2438                                 }
2439                                 base= base->next;
2440                         }
2441                 }
2442
2443                 if(event==0) BIF_undo_push("Insert Loc Key");
2444                 else if(event==1) BIF_undo_push("Insert Rot Key");
2445                 else if(event==2) BIF_undo_push("Insert Size Key");
2446                 else if(event==3) BIF_undo_push("Insert LocRot Key");
2447                 else if(event==4) BIF_undo_push("Insert LocRotSize Key");
2448                 else if(event==5) BIF_undo_push("Insert Layer Key");
2449                 else if(event==7) BIF_undo_push("Insert Vertex Key");
2450                 else if(event==9) BIF_undo_push("Insert Avail Key");
2451
2452                 allspace(REMAKEIPO, 0);
2453                 allqueue(REDRAWIPO, 0);
2454                 allqueue(REDRAWVIEW3D, 0);
2455                 allqueue(REDRAWACTION, 0);
2456                 allqueue(REDRAWNLA, 0);
2457         }
2458         
2459 }
2460
2461 /* ****************************************************************************** */
2462
2463 void add_duplicate_editipo(void)
2464 {
2465         Object *ob;
2466         EditIpo *ei;
2467         IpoCurve *icu;
2468         BezTriple *bezt, *beztn, *newb;
2469         int tot, a, b;
2470         
2471         get_status_editipo();
2472         if(totipo_vertsel==0) return;
2473         
2474         ei= G.sipo->editipo;
2475         for(a=0; a<G.sipo->totipo; a++, ei++) {
2476                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2477                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2478                                 icu= ei->icu;
2479                                 
2480                                 /* how many points */
2481                                 tot= 0;
2482                                 b= icu->totvert;
2483                                 bezt= icu->bezt;
2484                                 while(b--) {
2485                                         if(bezt->f2 & 1) tot++;
2486                                         bezt++;
2487                                 }
2488                                 
2489                                 if(tot) {
2490                                         icu->totvert+= tot;
2491                                         newb= beztn= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2492                                         bezt= icu->bezt;
2493                                         b= icu->totvert-tot;
2494                                         while(b--) {
2495                                                 *beztn= *bezt;
2496                                                 if(bezt->f2 & 1) {
2497                                                         beztn->f1= beztn->f2= beztn->f3= 0;
2498                                                         beztn++;
2499                                                         *beztn= *bezt;
2500                                                 }
2501                                                 beztn++;
2502                                                 bezt++;
2503                                         }
2504                                         MEM_freeN(icu->bezt);
2505                                         icu->bezt= newb;
2506                                         
2507                                         calchandles_ipocurve(icu);
2508                                 }
2509                         }
2510                 }
2511         }
2512         
2513         if(G.sipo->showkey) {
2514                 make_ipokey();
2515                 if(G.sipo->blocktype==ID_OB) {
2516                         ob= OBACT;
2517                         if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
2518                 }
2519         }
2520         BIF_undo_push("Duplicate Ipo");
2521         transform_ipo('g');
2522 }
2523
2524 void remove_doubles_ipo(void)
2525 {
2526         EditIpo *ei;
2527         IpoKey *ik, *ikn;
2528         BezTriple *bezt, *newb, *new1;
2529         float val;
2530         int mode, a, b;
2531         
2532         ei= G.sipo->editipo;
2533         for(a=0; a<G.sipo->totipo; a++, ei++) {
2534                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2535                         
2536                         /* OR the curve is selected OR in editmode OR in keymode */
2537                         mode= 0;
2538                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) mode= 1;
2539                         else if(ei->flag & IPO_SELECT) mode= 2;
2540                         
2541                         if(mode) {
2542                                 bezt= ei->icu->bezt;
2543                                 newb= new1= MEM_mallocN(ei->icu->totvert*sizeof(BezTriple), "newbezt");
2544                                 *newb= *bezt;
2545                                 b= ei->icu->totvert-1;
2546                                 bezt++;
2547                                 while(b--) {
2548                                         
2549                                         /* can we remove? */
2550                                         if(mode==2 || (bezt->f2 & 1)) {
2551                                         
2552                                                 /* are the points different? */
2553                                                 if( fabs( bezt->vec[1][0]-newb->vec[1][0] ) > 0.9 ) {
2554                                                         newb++;
2555                                                         *newb= *bezt;
2556                                                 }
2557                                                 else {
2558                                                         /* median */
2559                                                         VecMidf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2560                                                         VecMidf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2561                                                         VecMidf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2562                                                         
2563                                                         newb->h1= newb->h2= HD_FREE;
2564                                                         
2565                                                         ei->icu->totvert--;
2566                                                 }
2567                                                 
2568                                         }
2569                                         else {
2570                                                 newb++;
2571                                                 *newb= *bezt;
2572                                         }
2573                                         bezt++;
2574                                 }
2575                                 
2576                                 MEM_freeN(ei->icu->bezt);
2577                                 ei->icu->bezt= new1;
2578                                 
2579                                 calchandles_ipocurve(ei->icu);                          
2580                         }
2581                 }
2582         }
2583         
2584         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2585
2586         /* remove double keys */
2587         if(G.sipo->showkey) {
2588                 ik= G.sipo->ipokey.first;
2589                 ikn= ik->next;
2590                 
2591                 while(ik && ikn) {
2592                         if( (ik->flag & 1) && (ikn->flag & 1) ) {
2593                                 if( fabs(ik->val-ikn->val) < 0.9 ) {
2594                                         val= (float)((ik->val + ikn->val)/2.0);
2595                                         
2596                                         for(a=0; a<G.sipo->totipo; a++) {
2597                                                 if(ik->data[a]) ik->data[a]->vec[1][0]= val;
2598                                                 if(ikn->data[a]) ikn->data[a]->vec[1][0]= val;                                          
2599                                         }
2600                                 }
2601                         }
2602                         ik= ikn;
2603                         ikn= ikn->next;
2604
2605                 }
2606                 
2607                 editipo_changed(G.sipo, 1);     /* makes ipokeys agian! */
2608
2609         }
2610         deselectall_editipo();
2611 }
2612
2613 void join_ipo_menu(void)
2614 {
2615         int mode = 0;
2616         mode= pupmenu("Join %t|All Selected %x1|Selected Doubles %x2");
2617         
2618         if (mode == -1) return;
2619         
2620         join_ipo(mode);
2621 }
2622
2623 void join_ipo(int mode)
2624 {
2625         EditIpo *ei;
2626         IpoKey *ik;
2627         IpoCurve *icu;
2628         BezTriple *bezt, *beztn, *newb;
2629         float val;
2630         int tot, a, b;
2631         
2632         get_status_editipo();
2633         
2634         /* Mode events:
2635          * All Selected: 1
2636          * Selected Doubles: 2
2637          */
2638         
2639         if( mode==2 ) {
2640                 remove_doubles_ipo();
2641                 return;
2642         }
2643         
2644         /* first: multiple selected verts in 1 curve */
2645         ei= G.sipo->editipo;
2646         for(a=0; a<G.sipo->totipo; a++, ei++) {
2647                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2648                         if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2649                                 icu= ei->icu;
2650                                 
2651                                 /* how many points */
2652                                 tot= 0;
2653                                 b= icu->totvert;
2654                                 bezt= icu->bezt;
2655                                 while(b--) {
2656                                         if(bezt->f2 & 1) tot++;
2657                                         bezt++;
2658                                 }
2659                                 
2660                                 if(tot>1) {
2661                                         tot--;
2662                                         icu->totvert-= tot;
2663                                         
2664                                         newb= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
2665                                         /* the first point is the new one */
2666                                         beztn= newb+1;
2667                                         tot= 0;
2668                                         
2669                                         bezt= icu->bezt;
2670                                         b= icu->totvert+tot+1;
2671                                         while(b--) {
2672                                                 
2673                                                 if(bezt->f2 & 1) {
2674                                                         if(tot==0) *newb= *bezt;
2675                                                         else {
2676                                                                 VecAddf(newb->vec[0], newb->vec[0], bezt->vec[0]);
2677                                                                 VecAddf(newb->vec[1], newb->vec[1], bezt->vec[1]);
2678                                                                 VecAddf(newb->vec[2], newb->vec[2], bezt->vec[2]);
2679                                                         }
2680                                                         tot++;
2681                                                 }
2682                                                 else {
2683                                                         *beztn= *bezt;
2684                                                         beztn++;
2685                                                 }
2686                                                 bezt++;
2687                                         }
2688                                         
2689                                         VecMulf(newb->vec[0], (float)(1.0/((float)tot)));
2690                                         VecMulf(newb->vec[1], (float)(1.0/((float)tot)));
2691                                         VecMulf(newb->vec[2], (float)(1.0/((float)tot)));
2692                                         
2693                                         MEM_freeN(icu->bezt);
2694                                         icu->bezt= newb;
2695                                         
2696                                         sort_time_ipocurve(icu);
2697                                         calchandles_ipocurve(icu);
2698                                 }
2699                         }
2700                 }
2701         }
2702         
2703         /* next: in keymode: join multiple selected keys */
2704         
2705         editipo_changed(G.sipo, 1);     /* makes ipokeys again! */
2706         
2707         if(G.sipo->showkey) {
2708                 ik= G.sipo->ipokey.first;
2709                 val= 0.0;
2710                 tot= 0;
2711                 while(ik) {
2712                         if(ik->flag & 1) {
2713                                 for(a=0; a<G.sipo->totipo; a++) {
2714                                         if(ik->data[a]) {
2715                                                 val+= ik->data[a]->vec[1][0];
2716                                                 break;
2717                                         }
2718                                 }
2719                                 tot++;
2720                         }
2721                         ik= ik->next;
2722                 }
2723                 if(tot>1) {
2724                         val/= (float)tot;
2725                         
2726                         ik= G.sipo->ipokey.first;
2727                         while(ik) {
2728                                 if(ik->flag & 1) {
2729                                         for(a=0; a<G.sipo->totipo; a++) {
2730                                                 if(ik->data[a]) {
2731                                                         ik->data[a]->vec[1][0]= val;
2732                                                 }
2733                                         }
2734                                 }
2735                                 ik= ik->next;
2736                         }
2737                         editipo_changed(G.sipo, 0);
2738                 }
2739         }
2740         deselectall_editipo();
2741         BIF_undo_push("Join Ipo");
2742 }
2743
2744 void ipo_snap_menu(void)
2745 {
2746         short event;
2747         
2748         event= pupmenu("Snap %t|Horizontal %x1|To Next %x2|To Frame %x3|To Current Frame%x4");
2749         if(event < 1) return;
2750
2751         ipo_snap(event);
2752 }
2753
2754 void ipo_snap(short event)
2755 {
2756         EditIpo *ei;
2757         BezTriple *bezt;
2758         float dx = 0.0;
2759         int a, b;
2760         short ok, ok2;
2761         
2762         /* events:
2763          * Horizontal : 1
2764          * To Next: 2
2765          * To Frame: 3
2766          * To Current Frame: 4
2767          */
2768          
2769         get_status_editipo();
2770
2771         ei= G.sipo->editipo;
2772         for(b=0; b<G.sipo->totipo; b++, ei++) {
2773                 if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
2774                 
2775                         ok2= 0;
2776                         if(G.sipo->showkey) ok2= 1;
2777                         else if(totipo_vert && (ei->flag & IPO_EDIT)) ok2= 2;
2778                         else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok2= 3;
2779                         
2780                         if(ok2) {
2781                                 bezt= ei->icu->bezt;
2782                                 a= ei->icu->totvert;
2783                                 while(a--) {
2784                                         ok= 0;
2785                                         if(totipo_vert) {
2786                                                  if(bezt->f2 & 1) ok= 1;
2787                                         }
2788                                         else ok= 1;
2789                                         
2790                                         if(ok) {
2791                                                 if(event==1) {
2792                                                         bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
2793                                                         if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2794                                                         if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2795                                                 }
2796                                                 else if(event==2) {
2797                                                         if(a) {
2798                                                                 bezt->vec[0][1]= bezt->vec[1][1]= bezt->vec[2][1]= (bezt+1)->vec[1][1];
2799                                                                 if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
2800                                                                 if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
2801                                                         }
2802                                                 }
2803                                                 else if(event==3) {
2804                                                         bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
2805                                                 }
2806                                                 else if(event==4) {     /* to current frame */
2807                                                         
2808                                                         if(ok2==1 || ok2==2) {
2809                                                                 
2810                                                                 if(G.sipo->blocktype==ID_SEQ) {
2811                                                                         Sequence *seq;
2812                                                         
2813                                                                         seq= (Sequence *)G.sipo->from;
2814                                                                         if(seq) {
2815                                                                                 dx= (float)(CFRA-seq->startdisp);
2816                                                                                 dx= (float)(100.0*dx/((float)(seq->enddisp-seq->startdisp)));
2817                                                                                 
2818                                                                                 dx-= bezt->vec[1][0];
2819                                                                         }
2820                                                                 }
2821                                                                 else dx= G.scene->r.framelen*CFRA - bezt->vec[1][0];
2822                                                                 
2823                                                                 bezt->vec[0][0]+= dx;
2824                                                                 bezt->vec[1][0]+= dx;
2825                                                                 bezt->vec[2][0]+= dx;
2826                                                         }
2827                                                 }
2828                                         }
2829                                         
2830                                         bezt++;
2831                                 }
2832                                 calchandles_ipocurve(ei->icu);
2833                         }
2834                 }
2835         }
2836         editipo_changed(G.sipo, 1);
2837         BIF_undo_push("Snap Ipo");
2838 }
2839
2840 /*
2841  * When deleting an IPO curve from Python, check if the Ipo is being
2842  * edited and if so clear the pointer to the old curve.
2843  */
2844
2845 void del_ipoCurve ( IpoCurve * icu )
2846 {
2847         int i;
2848         EditIpo *ei= G.sipo->editipo;
2849         if (!ei) return;
2850
2851         for(i=0; i<G.sipo->totipo; i++, ei++) {
2852                 if ( ei->icu == icu ) {
2853                         ei->flag &= ~(IPO_SELECT | IPO_EDIT);
2854                         ei->icu= NULL;
2855                         return;
2856                 }
2857         }
2858 }
2859
2860 void del_ipo(void)
2861 {
2862         EditIpo *ei;
2863         BezTriple *bezt, *bezt1;
2864         int a, b;
2865         int del, event;
2866
2867         get_status_editipo();
2868         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
2869         
2870         if(totipo_edit==0 && totipo_sel==0 && totipo_vertsel==0) {
2871                 if(okee("Erase selected keys"))
2872                    delete_key(OBACT);
2873                 return;
2874         }
2875         
2876         if( okee("Erase selected")==0 ) return;
2877
2878         // first round, can we delete entire parts? 
2879         ei= G.sipo->editipo;
2880         for(a=0; a<G.sipo->totipo; a++, ei++) {
2881         
2882                 del= 0;
2883                 
2884                 if(G.sipo->showkey==0 && totipo_edit==0) {
2885                         if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
2886                                 del= 1;
2887                         }
2888                 }
2889                 else {
2890                         if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
2891                                 if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
2892                                         if(ei->icu->bezt) {
2893                                                 bezt= ei->icu->bezt;
2894                                                 b= ei->icu->totvert;
2895                                                 if(b) {
2896                                                         while(b) {
2897                                                                 if( BEZSELECTED(bezt) );
2898                                                                 else break;
2899                                                                 b--;
2900                                                                 bezt++;
2901                                                         }
2902                                                         if(b==0) del= 1;
2903                                                 }
2904                                         }
2905                                 }
2906                         }
2907                 }