- removed makeDispList, set_displist_onlyzero
[blender.git] / source / blender / src / editkey.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <math.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifndef WIN32
40 #include <unistd.h>
41 #else
42 #include <io.h>
43 #endif   
44 #include "MEM_guardedalloc.h"
45
46 #include "BLI_blenlib.h"
47 #include "BLI_arithb.h"
48
49 #include "DNA_curve_types.h"
50 #include "DNA_ipo_types.h"
51 #include "DNA_key_types.h"
52 #include "DNA_mesh_types.h"
53 #include "DNA_meshdata_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_screen_types.h"
56 #include "DNA_space_types.h"
57 #include "DNA_userdef_types.h"
58 #include "DNA_view2d_types.h"
59 #include "DNA_lattice_types.h"
60 #include "DNA_scene_types.h"
61
62 #include "BKE_anim.h"
63 #include "BKE_curve.h"
64 #include "BKE_depsgraph.h"
65 #include "BKE_global.h"
66 #include "BKE_ipo.h"
67 #include "BKE_key.h"
68 #include "BKE_library.h"
69 #include "BKE_main.h"
70 #include "BKE_object.h"
71 #include "BKE_utildefines.h"
72
73 #include "BIF_editkey.h"
74 #include "BIF_editview.h"
75 #include "BIF_mywindow.h"
76 #include "BIF_screen.h"
77 #include "BIF_space.h"
78 #include "BIF_toolbox.h"
79 #include "BIF_interface.h"
80
81 #include "BSE_editipo.h"
82 #include "BSE_trans_types.h"
83
84 #include "BDR_editobject.h"
85
86 #include "blendef.h"
87 #include "mydevice.h"
88
89 extern ListBase editNurb; /* in editcurve.c */
90
91
92 /* local prototypes ------------------ */
93 void make_rvk_slider(uiBlock *, Key *, int , int , int , int , int );  /* used in drawaction.c too */
94
95 /* temporary storage for slider values */
96 float meshslidervals[64] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
97                             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
98                             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
99                             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
100                                                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
101                             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
102                             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
103                             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
104
105 static IpoCurve *get_key_icu(Key *key, int keynum) {
106         /* return the Ipocurve that has the specified
107          * keynum as ardcode -- return NULL if no such 
108          * curve exists.
109          */
110     IpoCurve *icu;
111         if (!(key->ipo)) {
112                 key->ipo = get_ipo((ID *)key, ID_KE, 1);
113                 return NULL;
114         }
115
116
117     for (icu = key->ipo->curve.first; icu ; icu = icu->next) {
118         if (!icu->adrcode) continue;
119         if (icu->adrcode == keynum) return icu;
120     }
121
122     return NULL;
123 }
124
125 static BezTriple *get_bezt_icu_time(IpoCurve *icu, float *frame, float *val) {
126         /* this function tries to find a bezier that is within
127          * 0.25 time units from the specified frame. If there
128          * are more than one such beziers, it returns the
129          * closest one.
130          */
131         int   i;
132         float d, dmin = 0.25, newframe;
133         BezTriple *bezt = NULL;
134         
135         newframe = *frame;
136
137         for (i=0; i<icu->totvert; i++){
138                 d = fabs(icu->bezt[i].vec[1][0] - *frame);
139                 if (d < dmin) {
140                         dmin     = d;
141                         newframe = icu->bezt[i].vec[1][0];
142                         *val     = icu->bezt[i].vec[1][1];
143                         bezt     = icu->bezt + i;
144                 }
145         }
146
147         *frame = newframe;
148         return bezt;
149 }
150
151 static void rvk_slider_func(void *voidkey, void *voidkeynum) 
152 {
153         /* the callback for the rvk sliders ... copies the
154          * value from the temporary array into a bezier at the
155          * right frame on the right ipo curve (creating both the
156          * ipo curve and the bezier if needed).
157          */
158         IpoCurve  *icu=NULL;
159         BezTriple *bezt=NULL;
160         Key       *key = (Key *) voidkey;
161         float     cfra, rvkval;
162         int       *keynum = (int *) voidkeynum;
163
164         cfra = frame_to_float(CFRA);
165
166         icu = get_key_icu(key, *keynum);
167
168         if (icu) {
169                 /* if the ipocurve exists, try to get a bezier
170                  * for this frame
171                  */
172                 bezt = get_bezt_icu_time(icu, &cfra, &rvkval);
173         }
174         else {
175                 /* create an IpoCurve if one doesn't already
176                  * exist.
177                  */
178                 icu = get_ipocurve(key->from, GS(key->from->name), 
179                                                    *keynum, key->ipo);
180         }
181         
182         /* create the bezier triple if one doesn't exist,
183          * otherwise modify it's value
184          */
185         if (!bezt) {
186                 insert_vert_ipo(icu, cfra, meshslidervals[*keynum]);
187         }
188         else {
189                 bezt->vec[1][1] = meshslidervals[*keynum];
190         }
191
192         /* make sure the Ipo's are properly process and
193          * redraw as necessary
194          */
195         sort_time_ipocurve(icu);
196         testhandles_ipocurve(icu);
197
198         key->flag &= ~KEY_LOCKED;
199         do_ipo(key->ipo);
200         do_spec_key(key);
201         
202         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
203         
204         allqueue (REDRAWVIEW3D, 0);
205         allqueue (REDRAWACTION, 0);
206         allqueue (REDRAWNLA, 0);
207         allqueue (REDRAWIPO, 0);
208
209 }
210
211 static float getrvkval(Key *key, int keynum) {
212         /* get the value of the rvk from the
213          * ipo curve at the current time -- return 0
214          * if no ipo curve exists
215          */
216         IpoCurve  *icu=NULL;
217         BezTriple *bezt=NULL;
218         float     rvkval = 0.0;
219         float     cfra;
220
221         cfra = frame_to_float(CFRA);
222         icu    = get_key_icu(key, keynum);
223         if (icu) {
224                 bezt = get_bezt_icu_time(icu, &cfra, &rvkval);
225                 if (!bezt) {
226                         rvkval = eval_icu(icu, cfra);
227                 }
228         }
229
230         return rvkval;
231
232 }
233
234 void make_rvk_slider(uiBlock *block, Key *key, int keynum,
235                                          int x, int y, int w, int h)
236 {
237         /* create a slider for the rvk */
238         uiBut         *but;
239         KeyBlock   *kb;
240         float min, max;
241         int i;
242
243         /* dang, need to pass a pointer to int to uiButSetFunc
244          * that is on the heap, not the stack ... hence this
245          * kludgy static array
246          */
247         static int keynums[] = {0,1,2,3,4,5,6,7,
248                                                         8,9,10,11,12,13,14,15,
249                                                         16,17,18,19,20,21,22,23,
250                                                         24,25,26,27,28,29,30,31,
251                                                         32,33,34,35,36,37,38,39,
252                                                         40,41,42,43,44,45,46,47,
253                                                         48,49,50,51,52,53,54,55,
254                                                         56,57,58,59,60,61,62,63};
255
256         meshslidervals[keynum] = getrvkval(key, keynum);
257
258         kb= key->block.first;
259         for (i=0; i<keynum; ++i) kb = kb->next; 
260
261         if ( (kb->slidermin >= kb->slidermax) ) {
262                 kb->slidermin = 0.0;
263                 kb->slidermax = 1.0;
264         }
265
266         min = (kb->slidermin < meshslidervals[keynum]) ? 
267                 kb->slidermin: meshslidervals[keynum];
268
269         max = (kb->slidermax > meshslidervals[keynum]) ? 
270                 kb->slidermax: meshslidervals[keynum];
271
272         but=uiDefButF(block, NUMSLI, REDRAWVIEW3D, "",
273                                   x, y , w, h,
274                                   meshslidervals+keynum, min, max, 10, 2,
275                                   "Slider to control rvk");
276         uiButSetFunc(but, rvk_slider_func, key, keynums+keynum);
277         // no hilite, the winmatrix is not correct later on...
278         uiButSetFlag(but, UI_NO_HILITE);
279
280 }
281
282 static void default_key_ipo(Key *key)
283 {
284         IpoCurve *icu;
285         BezTriple *bezt;
286         
287         key->ipo= add_ipo("KeyIpo", ID_KE);
288         
289         icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
290                         
291         icu->blocktype= ID_KE;
292         icu->adrcode= KEY_SPEED;
293         icu->flag= IPO_VISIBLE|IPO_SELECT|IPO_AUTO_HORIZ;
294         set_icu_vars(icu);
295         
296         BLI_addtail( &(key->ipo->curve), icu);
297         
298         icu->bezt= bezt= MEM_callocN(2*sizeof(BezTriple), "defaultipo");
299         icu->totvert= 2;
300         
301         bezt->hide= IPO_BEZ;
302         bezt->f1=bezt->f2= bezt->f3= SELECT;
303         bezt->h1= bezt->h2= HD_AUTO;
304         bezt++;
305         bezt->vec[1][0]= 100.0;
306         bezt->vec[1][1]= 1.0;
307         bezt->hide= IPO_BEZ;
308         bezt->f1=bezt->f2= bezt->f3= SELECT;
309         bezt->h1= bezt->h2= HD_AUTO;
310         
311         calchandles_ipocurve(icu);
312 }
313
314         
315
316 /* **************************************** */
317
318 void mesh_to_key(Mesh *me, KeyBlock *kb)
319 {
320         MVert *mvert;
321         float *fp;
322         int a;
323         
324         if(me->totvert==0) return;
325         
326         if(kb->data) MEM_freeN(kb->data);
327         
328         kb->data= MEM_callocN(me->key->elemsize*me->totvert, "kb->data");
329         kb->totelem= me->totvert;
330         
331         mvert= me->mvert;
332         fp= kb->data;
333         for(a=0; a<kb->totelem; a++, fp+=3, mvert++) {
334                 VECCOPY(fp, mvert->co);
335                 
336         }
337 }
338
339 void key_to_mesh(KeyBlock *kb, Mesh *me)
340 {
341         MVert *mvert;
342         float *fp;
343         int a, tot;
344         
345         mvert= me->mvert;
346         fp= kb->data;
347         
348         tot= MIN2(kb->totelem, me->totvert);
349         
350         for(a=0; a<tot; a++, fp+=3, mvert++) {
351                 VECCOPY(mvert->co, fp);
352         }
353 }
354
355
356
357 void insert_meshkey(Mesh *me, short offline)
358 {
359         Key *key;
360         KeyBlock *kb, *kkb;
361         float curpos;
362         short rel;
363
364         if(me->key==0) {
365                 me->key= add_key( (ID *)me);
366
367                 if (!offline) /* interactive */
368                         rel = pupmenu("Insert Vertex Keys %t|"
369                                                                                 "Relative Keys %x1|Absolute Keys %x2");
370                 else /* we were called from a script */
371                         rel = offline;
372
373                 switch (rel) {
374                 case 1:
375                         me->key->type = KEY_RELATIVE;
376                         break;
377                 default:
378                         default_key_ipo(me->key);
379                         break;
380                 }
381         }
382         key= me->key;
383         
384         kb= MEM_callocN(sizeof(KeyBlock), "Keyblock");
385         BLI_addtail(&key->block, kb);
386         kb->type= KEY_CARDINAL;
387         
388         curpos= bsystem_time(0, 0, (float)CFRA, 0.0);
389         if(calc_ipo_spec(me->key->ipo, KEY_SPEED, &curpos)==0) {
390                 curpos /= 100.0;
391         }
392         kb->pos= curpos;
393         
394         key->totkey++;
395         if(key->totkey==1) key->refkey= kb;
396         
397         mesh_to_key(me, kb);
398         
399         sort_keys(me->key);
400
401         /* curent active: */
402         kkb= key->block.first;
403         while(kkb) {
404                 kkb->flag &= ~SELECT;
405                 if(kkb==kb) kkb->flag |= SELECT;
406                 
407                 kkb= kkb->next;
408         }
409 }
410
411 /* ******************** */
412
413 void latt_to_key(Lattice *lt, KeyBlock *kb)
414 {
415         BPoint *bp;
416         float *fp;
417         int a, tot;
418         
419         tot= lt->pntsu*lt->pntsv*lt->pntsw;
420         if(tot==0) return;
421         
422         if(kb->data) MEM_freeN(kb->data);
423         
424         kb->data= MEM_callocN(lt->key->elemsize*tot, "kb->data");
425         kb->totelem= tot;
426         
427         bp= lt->def;
428         fp= kb->data;
429         for(a=0; a<kb->totelem; a++, fp+=3, bp++) {
430                 VECCOPY(fp, bp->vec);
431         }
432 }
433
434 void key_to_latt(KeyBlock *kb, Lattice *lt)
435 {
436         BPoint *bp;
437         float *fp;
438         int a, tot;
439         
440         bp= lt->def;
441         fp= kb->data;
442         
443         tot= lt->pntsu*lt->pntsv*lt->pntsw;
444         tot= MIN2(kb->totelem, tot);
445         
446         for(a=0; a<tot; a++, fp+=3, bp++) {
447                 VECCOPY(bp->vec, fp);
448         }
449         
450 }
451
452 void insert_lattkey(Lattice *lt)
453 {
454         Key *key;
455         KeyBlock *kb, *kkb;
456         float curpos;
457         
458         if(lt->key==0) {
459                 lt->key= add_key( (ID *)lt);
460                 default_key_ipo(lt->key);
461         }
462         key= lt->key;
463         
464         kb= MEM_callocN(sizeof(KeyBlock), "Keyblock");
465         BLI_addtail(&key->block, kb);
466         kb->type= KEY_CARDINAL;
467         
468         curpos= bsystem_time(0, 0, (float)CFRA, 0.0);
469         if(calc_ipo_spec(lt->key->ipo, KEY_SPEED, &curpos)==0) {
470                 curpos /= 100.0;
471         }
472         kb->pos= curpos;
473         
474         key->totkey++;
475         if(key->totkey==1) key->refkey= kb;
476         
477         latt_to_key(lt, kb);
478         
479         sort_keys(lt->key);
480
481         /* curent active: */
482         kkb= key->block.first;
483         while(kkb) {
484                 kkb->flag &= ~SELECT;
485                 if(kkb==kb) kkb->flag |= SELECT;
486                 
487                 kkb= kkb->next;
488         }
489 }
490
491 /* ******************************** */
492
493 void curve_to_key(Curve *cu, KeyBlock *kb, ListBase *nurb)
494 {
495         Nurb *nu;
496         BezTriple *bezt;
497         BPoint *bp;
498         float *fp;
499         int a, tot;
500         
501         /* count */
502         tot= count_curveverts(nurb);
503         if(tot==0) return;
504         
505         if(kb->data) MEM_freeN(kb->data);
506         
507         kb->data= MEM_callocN(cu->key->elemsize*tot, "kb->data");
508         kb->totelem= tot;
509         
510         nu= nurb->first;
511         fp= kb->data;
512         while(nu) {
513                 
514                 if(nu->bezt) {
515                         bezt= nu->bezt;
516                         a= nu->pntsu;
517                         while(a--) {
518                                 VECCOPY(fp, bezt->vec[0]);
519                                 fp+= 3;
520                                 VECCOPY(fp, bezt->vec[1]);
521                                 fp+= 3;
522                                 VECCOPY(fp, bezt->vec[2]);
523                                 fp+= 3;
524                                 fp[0]= bezt->alfa;
525                                 fp+= 3; /* alphas */
526                                 bezt++;
527                         }
528                 }
529                 else {
530                         bp= nu->bp;
531                         a= nu->pntsu*nu->pntsv;
532                         while(a--) {
533                                 VECCOPY(fp, bp->vec);
534                                 fp[3]= bp->alfa;
535                                 
536                                 fp+= 4;
537                                 bp++;
538                         }
539                 }
540                 nu= nu->next;
541         }
542 }
543
544 void key_to_curve(KeyBlock *kb, Curve  *cu, ListBase *nurb)
545 {
546         Nurb *nu;
547         BezTriple *bezt;
548         BPoint *bp;
549         float *fp;
550         int a, tot;
551         
552         nu= nurb->first;
553         fp= kb->data;
554         
555         tot= count_curveverts(nurb);
556
557         tot= MIN2(kb->totelem, tot);
558         
559         while(nu && tot>0) {
560                 
561                 if(nu->bezt) {
562                         bezt= nu->bezt;
563                         a= nu->pntsu;
564                         while(a-- && tot>0) {
565                                 VECCOPY(bezt->vec[0], fp);
566                                 fp+= 3;
567                                 VECCOPY(bezt->vec[1], fp);
568                                 fp+= 3;
569                                 VECCOPY(bezt->vec[2], fp);
570                                 fp+= 3;
571                                 bezt->alfa= fp[0];
572                                 fp+= 3; /* alphas */
573                         
574                                 tot-= 3;
575                                 bezt++;
576                         }
577                 }
578                 else {
579                         bp= nu->bp;
580                         a= nu->pntsu*nu->pntsv;
581                         while(a-- && tot>0) {
582                                 VECCOPY(bp->vec, fp);
583                                 bp->alfa= fp[3];
584                                 
585                                 fp+= 4;
586                                 tot--;
587                                 bp++;
588                         }
589                 }
590                 nu= nu->next;
591         }
592 }
593
594
595
596 void insert_curvekey(Curve *cu)
597 {
598         Key *key;
599         KeyBlock *kb, *kkb;
600         float curpos;
601         
602         if(cu->key==0) {
603                 cu->key= add_key( (ID *)cu);
604                 default_key_ipo(cu->key);
605         }
606         key= cu->key;
607         
608         kb= MEM_callocN(sizeof(KeyBlock), "Keyblock");
609         BLI_addtail(&key->block, kb);
610         kb->type= KEY_CARDINAL;
611         
612         curpos= bsystem_time(0, 0, (float)CFRA, 0.0);
613         if(calc_ipo_spec(cu->key->ipo, KEY_SPEED, &curpos)==0) {
614                 curpos /= 100.0;
615         }
616         kb->pos= curpos;
617         
618         key->totkey++;
619         if(key->totkey==1) key->refkey= kb;
620         
621         if(editNurb.first) curve_to_key(cu, kb, &editNurb);
622         else curve_to_key(cu, kb, &cu->nurb);
623         
624         sort_keys(cu->key);
625
626         /* curent active: */
627         kkb= key->block.first;
628         while(kkb) {
629                 kkb->flag &= ~SELECT;
630                 if(kkb==kb) kkb->flag |= SELECT;
631                 
632                 kkb= kkb->next;
633         }
634 }
635
636
637 /* ******************** */
638
639 Key *give_current_key(Object *ob)
640 {
641         Mesh *me;
642         Curve *cu;
643         Lattice *lt;
644         
645         if(ob->type==OB_MESH) {
646                 me= ob->data;
647                 return me->key;
648         }
649         else if ELEM(ob->type, OB_CURVE, OB_SURF) {
650                 cu= ob->data;
651                 return cu->key;
652         }
653         else if(ob->type==OB_LATTICE) {
654                 lt= ob->data;
655                 return lt->key;
656         }
657         return 0;
658 }
659
660 void showkeypos(Key *key, KeyBlock *kb)
661 {
662         Object *ob;
663         Mesh *me;
664         Lattice *lt;
665         Curve *cu;
666         int tot;
667         
668         /* from ipo */
669         ob= OBACT;
670         if(ob==NULL) return;
671         
672         if(key == give_current_key(ob)) {
673                  
674                         // key lock is for when a key is selected in the ipo window,
675                         // it should be displayed in the 3d window then even though it
676                         // is not actually for the current frame. this is not the best
677                         // UI... - zr
678                 key->flag |= KEY_LOCKED;
679                 
680                 if(ob->type==OB_MESH) {
681                         me= ob->data;
682
683                         cp_key(0, me->totvert, me->totvert, (char *)me->mvert->co, me->key, kb, 0);
684                 }
685                 else if(ob->type==OB_LATTICE) {
686                         lt= ob->data;
687                         tot= lt->pntsu*lt->pntsv*lt->pntsw;
688                         
689                         cp_key(0, tot, tot, (char *)lt->def->vec, lt->key, kb, 0);
690                 }
691                 else if ELEM(ob->type, OB_CURVE, OB_SURF) {
692                         cu= ob->data;
693                         tot= count_curveverts(&cu->nurb);
694                         cp_cu_key(cu, kb, 0, tot);
695                 }
696                 
697                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
698                 
699                 allqueue(REDRAWVIEW3D, 0);
700         }
701 }
702
703 void deselectall_key(void)
704 {
705         KeyBlock *kb;
706         Key *key;
707         
708         if(G.sipo->blocktype!=ID_KE) return;
709         key= (Key *)G.sipo->from;
710         if(key==0) return;
711         
712         kb= key->block.first;
713         while(kb) {
714                 kb->flag &= ~SELECT;
715                 kb= kb->next;
716         }
717 }
718
719
720 void delete_key(void)
721 {
722         KeyBlock *kb, *kbn;
723         Key *key;
724         
725         if(G.sipo->blocktype!=ID_KE) return;
726
727         if(okee("Erase selected keys")==0) return;
728         
729         key= (Key *)G.sipo->from;
730         if(key==0) return;
731         
732         kb= key->block.first;
733         while(kb) {
734                 kbn= kb->next;
735                 if(kb->flag & SELECT) {
736                         BLI_remlink(&key->block, kb);
737                         key->totkey--;
738                         if(key->refkey== kb) key->refkey= key->block.first;
739                         
740                         if(kb->data) MEM_freeN(kb->data);
741                         MEM_freeN(kb);
742                         
743                 }
744                 kb= kbn;
745         }
746         
747         if(key->totkey==0) {
748                 if(GS(key->from->name)==ID_ME) ((Mesh *)key->from)->key= 0;
749                 else if(GS(key->from->name)==ID_CU) ((Curve *)key->from)->key= 0;
750                 else if(GS(key->from->name)==ID_LT) ((Lattice *)key->from)->key= 0;
751
752                 free_libblock_us(&(G.main->key), key);
753                 scrarea_queue_headredraw(curarea);      /* ipo remove too */
754         }
755         else {
756                 key->flag &= ~KEY_LOCKED;
757                 do_spec_key(key);
758         }
759         
760         allqueue(REDRAWVIEW3D, 0);
761         scrarea_queue_winredraw(curarea);
762 }
763
764 void move_keys(void)
765 {
766         Key *key;
767         KeyBlock *kb;
768         TransVert *transmain, *tv;
769         float div, dy, vec[3], dvec[3];
770         int a, tot=0, afbreek=0, firsttime= 1;
771         unsigned short event = 0;
772         short mval[2], val, xo, yo;
773         char str[32];
774         
775         if(G.sipo->blocktype!=ID_KE) return;
776         
777         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
778         if(G.sipo->editipo==0) return;
779
780         key= (Key *)G.sipo->from;
781         if(key==0) return;
782         
783         /* which keys are involved */
784         kb= key->block.first;
785         while(kb) {
786                 if(kb->flag & SELECT) tot++;
787                 kb= kb->next;
788         }
789         
790         if(tot==0) return;      
791         
792         tv=transmain= MEM_callocN(tot*sizeof(TransVert), "transmain");
793         kb= key->block.first;
794         while(kb) {
795                 if(kb->flag & SELECT) {
796                         tv->loc= &kb->pos;
797                         tv->oldloc[0]= kb->pos;
798                         tv++;
799                 }
800                 kb= kb->next;
801         }
802         
803         getmouseco_areawin(mval);
804         xo= mval[0];
805         yo= mval[1];
806         dvec[0]=dvec[1]=dvec[2]= 0.0; 
807         
808
809         while(afbreek==0) {
810                 getmouseco_areawin(mval);
811                 if(mval[0]!=xo || mval[1]!=yo || firsttime) {
812                         firsttime= 0;
813                         
814                         dy= (float)(mval[1]- yo);
815
816                         div= (float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
817                         dvec[1]+= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/div;
818                         
819                         VECCOPY(vec, dvec);
820
821                         apply_keyb_grid(vec, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
822                         apply_keyb_grid(vec+1, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
823
824                         tv= transmain;
825                         for(a=0; a<tot; a++, tv++) {
826                                 tv->loc[0]= tv->oldloc[0]+vec[1];
827                         }
828                         
829                         sprintf(str, "Y: %.3f  ", vec[1]);
830                         headerprint(str);
831                         
832                         xo= mval[0];
833                         yo= mval[1];
834                                 
835                         force_draw(0);
836                 }
837                 else BIF_wait_for_statechange();
838                 
839                 while(qtest()) {
840                         event= extern_qread(&val);
841                         if(val) {
842                                 switch(event) {
843                                 case ESCKEY:
844                                 case LEFTMOUSE:
845                                 case SPACEKEY:
846                                         afbreek= 1;
847                                         break;
848                                 default:
849                                         arrows_move_cursor(event);
850                                 }
851                         }
852                 }
853         }
854         
855         if(event==ESCKEY) {
856                 tv= transmain;
857                 for(a=0; a<tot; a++, tv++) {
858                         tv->loc[0]= tv->oldloc[0];
859                 }
860         }
861         
862         sort_keys(key);
863         key->flag &= ~KEY_LOCKED;
864         do_spec_key(key);
865         
866         /* for boundbox */
867         editipo_changed(G.sipo, 0);
868
869         MEM_freeN(transmain);   
870         allqueue(REDRAWVIEW3D, 0);
871         scrarea_queue_redraw(curarea);
872 }