Two in one:
[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 #include <string.h>
35
36 #ifndef WIN32
37 #include <unistd.h>
38 #else
39 #include <io.h>
40 #endif   
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_arithb.h"
46
47 #include "DNA_action_types.h"
48 #include "DNA_curve_types.h"
49 #include "DNA_ipo_types.h"
50 #include "DNA_key_types.h"
51 #include "DNA_lattice_types.h"
52 #include "DNA_mesh_types.h"
53 #include "DNA_meshdata_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_screen_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_view2d_types.h"
60
61 #include "BKE_action.h"
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 /* temporary storage for slider values */
92 /* pretty bad static stuff... is secured in drawaction.c though */
93 float meshslidervals[256] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
94                             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
95                             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
96                             0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 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, 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, 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, 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, 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, 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, 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, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
104                                                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
105                                                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
106                                                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
107                                                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
108                                                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
109
110 static IpoCurve *get_key_icu(Ipo *ipo, int keynum) 
111 {
112         /* return the Ipocurve that has the specified
113          * keynum as ardcode -- return NULL if no such 
114          * curve exists.
115          */
116     IpoCurve *icu;
117         
118         if (!ipo) 
119                 return NULL;
120
121     for (icu = ipo->curve.first; icu ; icu = icu->next) {
122         if (!icu->adrcode) continue;
123         if (icu->adrcode == keynum) return icu;
124     }
125
126     return NULL;
127 }
128
129 static BezTriple *get_bezt_icu_time(IpoCurve *icu, float *frame, float *val) {
130         /* this function tries to find a bezier that is within
131          * 0.25 time units from the specified frame. If there
132          * are more than one such beziers, it returns the
133          * closest one.
134          */
135         int   i;
136         float d, dmin = 0.25, newframe;
137         BezTriple *bezt = NULL;
138         
139         newframe = *frame;
140
141         for (i=0; i<icu->totvert; i++){
142                 d = fabs(icu->bezt[i].vec[1][0] - *frame);
143                 if (d < dmin) {
144                         dmin     = d;
145                         newframe = icu->bezt[i].vec[1][0];
146                         *val     = icu->bezt[i].vec[1][1];
147                         bezt     = icu->bezt + i;
148                 }
149         }
150
151         *frame = newframe;
152         return bezt;
153 }
154
155 static void rvk_slider_func(void *voidob, void *voidkeynum) 
156 {
157         /* the callback for the rvk sliders ... copies the
158          * value from the temporary array into a bezier at the
159          * right frame on the right ipo curve (creating both the
160          * ipo curve and the bezier if needed).
161          */
162         Object *ob= voidob;
163         IpoCurve  *icu=NULL;
164         BezTriple *bezt=NULL;
165         float cfra, rvkval;
166         int keynum = (int) voidkeynum;
167
168         cfra = frame_to_float(CFRA);
169
170         /* ipo on action or ob? */
171         if(ob->ipoflag & OB_ACTION_KEY)
172                 icu = verify_ipocurve(&ob->id, ID_KE, "Shape", NULL, keynum);
173         else 
174                 icu = verify_ipocurve(&ob->id, ID_KE, NULL, NULL, keynum);
175
176         if (icu) {
177                 /* if the ipocurve exists, try to get a bezier
178                  * for this frame
179                  */
180                 bezt = get_bezt_icu_time(icu, &cfra, &rvkval);
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                 ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
199                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
200         }
201         else error("Cannot edit this Shape Key");
202         
203         allqueue (REDRAWVIEW3D, 0);
204         allqueue (REDRAWACTION, 0);
205         allqueue (REDRAWNLA, 0);
206         allqueue (REDRAWIPO, 0);
207         allspace(REMAKEIPO, 0);
208 }
209
210 static float getrvkval(Ipo *ipo, int keynum) 
211 {
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(ipo, 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, Object *ob, int keynum,
235                                          int x, int y, int w, int h, char *tip)
236 {
237         /* create a slider for the rvk */
238         uiBut *but;
239         Ipo *ipo= NULL;
240         Key *key= ob_get_key(ob);
241         KeyBlock   *kb;
242         float min, max;
243         int i;
244         
245         if(key==NULL) return;
246         
247         /* ipo on action or ob? */
248         if(ob->ipoflag & OB_ACTION_KEY) {
249                 if(ob->action) {
250                         bActionChannel *achan;
251                         
252                         achan= get_action_channel(ob->action, "Shape");
253                         if(achan) ipo= achan->ipo;
254                 }
255         }
256         else ipo= key->ipo;
257         
258         /* global array */
259         meshslidervals[keynum] = getrvkval(ipo, keynum);
260
261         kb= key->block.first;
262         for (i=0; i<keynum; ++i) kb = kb->next; 
263
264         if ( (kb->slidermin >= kb->slidermax) ) {
265                 kb->slidermin = 0.0;
266                 kb->slidermax = 1.0;
267         }
268
269         min = (kb->slidermin < meshslidervals[keynum]) ? 
270                 kb->slidermin: meshslidervals[keynum];
271
272         max = (kb->slidermax > meshslidervals[keynum]) ? 
273                 kb->slidermax: meshslidervals[keynum];
274
275         but=uiDefButF(block, NUMSLI, REDRAWVIEW3D, "",
276                                   x, y , w, h,
277                                   meshslidervals+keynum, min, max, 10, 2, tip);
278         
279         uiButSetFunc(but, rvk_slider_func, ob, (void *)keynum);
280         // no hilite, the winmatrix is not correct later on...
281         uiButSetFlag(but, UI_NO_HILITE);
282
283 }
284
285 static void default_key_ipo(Key *key)
286 {
287         IpoCurve *icu;
288         BezTriple *bezt;
289         
290         key->ipo= add_ipo("KeyIpo", ID_KE);
291         
292         icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
293                         
294         icu->blocktype= ID_KE;
295         icu->adrcode= KEY_SPEED;
296         icu->flag= IPO_VISIBLE|IPO_SELECT|IPO_AUTO_HORIZ;
297         set_icu_vars(icu);
298         
299         BLI_addtail( &(key->ipo->curve), icu);
300         
301         icu->bezt= bezt= MEM_callocN(2*sizeof(BezTriple), "defaultipo");
302         icu->totvert= 2;
303         
304         bezt->hide= IPO_BEZ;
305         bezt->f1=bezt->f2= bezt->f3= SELECT;
306         bezt->h1= bezt->h2= HD_AUTO;
307         bezt++;
308         bezt->vec[1][0]= 100.0;
309         bezt->vec[1][1]= 1.0;
310         bezt->hide= IPO_BEZ;
311         bezt->f1=bezt->f2= bezt->f3= SELECT;
312         bezt->h1= bezt->h2= HD_AUTO;
313         
314         calchandles_ipocurve(icu);
315 }
316
317         
318
319 /* **************************************** */
320
321 void mesh_to_key(Mesh *me, KeyBlock *kb)
322 {
323         MVert *mvert;
324         float *fp;
325         int a;
326         
327         if(me->totvert==0) return;
328         
329         if(kb->data) MEM_freeN(kb->data);
330         
331         kb->data= MEM_callocN(me->key->elemsize*me->totvert, "kb->data");
332         kb->totelem= me->totvert;
333         
334         mvert= me->mvert;
335         fp= kb->data;
336         for(a=0; a<kb->totelem; a++, fp+=3, mvert++) {
337                 VECCOPY(fp, mvert->co);
338                 
339         }
340 }
341
342 void key_to_mesh(KeyBlock *kb, Mesh *me)
343 {
344         MVert *mvert;
345         float *fp;
346         int a, tot;
347         
348         mvert= me->mvert;
349         fp= kb->data;
350         
351         tot= MIN2(kb->totelem, me->totvert);
352         
353         for(a=0; a<tot; a++, fp+=3, mvert++) {
354                 VECCOPY(mvert->co, fp);
355         }
356 }
357
358 static KeyBlock *add_keyblock(Key *key)
359 {
360         KeyBlock *kb;
361         float curpos= -0.1;
362         int tot;
363         
364         kb= key->block.last;
365         if(kb) curpos= kb->pos;
366         
367         kb= MEM_callocN(sizeof(KeyBlock), "Keyblock");
368         BLI_addtail(&key->block, kb);
369         kb->type= KEY_CARDINAL;
370         tot= BLI_countlist(&key->block);
371         if(tot==1) strcpy(kb->name, "Basis");
372         else sprintf(kb->name, "Key %d", tot-1);
373         kb->adrcode= tot-1;
374         
375         key->totkey++;
376         if(key->totkey==1) key->refkey= kb;
377         
378         
379         if(key->type == KEY_RELATIVE) 
380                 kb->pos= curpos+0.1;
381         else {
382                 curpos= bsystem_time(0, 0, (float)CFRA, 0.0);
383                 if(calc_ipo_spec(key->ipo, KEY_SPEED, &curpos)==0) {
384                         curpos /= 100.0;
385                 }
386                 kb->pos= curpos;
387                 
388                 sort_keys(key);
389         }
390         return kb;
391 }
392
393 void insert_meshkey(Mesh *me, short rel)
394 {
395         Key *key;
396         KeyBlock *kb;
397
398         if(me->key==NULL) {
399                 me->key= add_key( (ID *)me);
400
401                 if(rel)
402                         me->key->type = KEY_RELATIVE;
403                 else
404                         default_key_ipo(me->key);
405         }
406         key= me->key;
407         
408         kb= add_keyblock(key);
409         
410         mesh_to_key(me, kb);
411 }
412
413 /* ******************** */
414
415 void latt_to_key(Lattice *lt, KeyBlock *kb)
416 {
417         BPoint *bp;
418         float *fp;
419         int a, tot;
420         
421         tot= lt->pntsu*lt->pntsv*lt->pntsw;
422         if(tot==0) return;
423         
424         if(kb->data) MEM_freeN(kb->data);
425         
426         kb->data= MEM_callocN(lt->key->elemsize*tot, "kb->data");
427         kb->totelem= tot;
428         
429         bp= lt->def;
430         fp= kb->data;
431         for(a=0; a<kb->totelem; a++, fp+=3, bp++) {
432                 VECCOPY(fp, bp->vec);
433         }
434 }
435
436 void key_to_latt(KeyBlock *kb, Lattice *lt)
437 {
438         BPoint *bp;
439         float *fp;
440         int a, tot;
441         
442         bp= lt->def;
443         fp= kb->data;
444         
445         tot= lt->pntsu*lt->pntsv*lt->pntsw;
446         tot= MIN2(kb->totelem, tot);
447         
448         for(a=0; a<tot; a++, fp+=3, bp++) {
449                 VECCOPY(bp->vec, fp);
450         }
451         
452 }
453
454 /* exported to python... hrms, should not, use object levels! (ton) */
455 void insert_lattkey(Lattice *lt, short rel)
456 {
457         Key *key;
458         KeyBlock *kb;
459         
460         if(lt->key==NULL) {
461                 lt->key= add_key( (ID *)lt);
462                 default_key_ipo(lt->key);
463         }
464         key= lt->key;
465         
466         kb= add_keyblock(key);
467         
468         latt_to_key(lt, kb);
469 }
470
471 /* ******************************** */
472
473 void curve_to_key(Curve *cu, KeyBlock *kb, ListBase *nurb)
474 {
475         Nurb *nu;
476         BezTriple *bezt;
477         BPoint *bp;
478         float *fp;
479         int a, tot;
480         
481         /* count */
482         tot= count_curveverts(nurb);
483         if(tot==0) return;
484         
485         if(kb->data) MEM_freeN(kb->data);
486         
487         kb->data= MEM_callocN(cu->key->elemsize*tot, "kb->data");
488         kb->totelem= tot;
489         
490         nu= nurb->first;
491         fp= kb->data;
492         while(nu) {
493                 
494                 if(nu->bezt) {
495                         bezt= nu->bezt;
496                         a= nu->pntsu;
497                         while(a--) {
498                                 VECCOPY(fp, bezt->vec[0]);
499                                 fp+= 3;
500                                 VECCOPY(fp, bezt->vec[1]);
501                                 fp+= 3;
502                                 VECCOPY(fp, bezt->vec[2]);
503                                 fp+= 3;
504                                 fp[0]= bezt->alfa;
505                                 fp+= 3; /* alphas */
506                                 bezt++;
507                         }
508                 }
509                 else {
510                         bp= nu->bp;
511                         a= nu->pntsu*nu->pntsv;
512                         while(a--) {
513                                 VECCOPY(fp, bp->vec);
514                                 fp[3]= bp->alfa;
515                                 
516                                 fp+= 4;
517                                 bp++;
518                         }
519                 }
520                 nu= nu->next;
521         }
522 }
523
524 void key_to_curve(KeyBlock *kb, Curve  *cu, ListBase *nurb)
525 {
526         Nurb *nu;
527         BezTriple *bezt;
528         BPoint *bp;
529         float *fp;
530         int a, tot;
531         
532         nu= nurb->first;
533         fp= kb->data;
534         
535         tot= count_curveverts(nurb);
536
537         tot= MIN2(kb->totelem, tot);
538         
539         while(nu && tot>0) {
540                 
541                 if(nu->bezt) {
542                         bezt= nu->bezt;
543                         a= nu->pntsu;
544                         while(a-- && tot>0) {
545                                 VECCOPY(bezt->vec[0], fp);
546                                 fp+= 3;
547                                 VECCOPY(bezt->vec[1], fp);
548                                 fp+= 3;
549                                 VECCOPY(bezt->vec[2], fp);
550                                 fp+= 3;
551                                 bezt->alfa= fp[0];
552                                 fp+= 3; /* alphas */
553                         
554                                 tot-= 3;
555                                 bezt++;
556                         }
557                 }
558                 else {
559                         bp= nu->bp;
560                         a= nu->pntsu*nu->pntsv;
561                         while(a-- && tot>0) {
562                                 VECCOPY(bp->vec, fp);
563                                 bp->alfa= fp[3];
564                                 
565                                 fp+= 4;
566                                 tot--;
567                                 bp++;
568                         }
569                 }
570                 nu= nu->next;
571         }
572 }
573
574
575 void insert_curvekey(Curve *cu, short rel) 
576 {
577         Key *key;
578         KeyBlock *kb;
579         
580         if(cu->key==NULL) {
581                 cu->key= add_key( (ID *)cu);
582
583                 if (rel)
584                         cu->key->type = KEY_RELATIVE;
585                 else
586                         default_key_ipo(cu->key);
587         }
588         key= cu->key;
589         
590         kb= add_keyblock(key);
591         
592         if(editNurb.first) curve_to_key(cu, kb, &editNurb);
593         else curve_to_key(cu, kb, &cu->nurb);
594 }
595
596
597 /* ******************** */
598
599 void insert_shapekey(Object *ob)
600 {
601         Key *key;
602         
603         if(ob->type==OB_MESH) insert_meshkey(ob->data, 1);
604         else if ELEM(ob->type, OB_CURVE, OB_SURF) insert_curvekey(ob->data, 1);
605         else if(ob->type==OB_LATTICE) insert_lattkey(ob->data, 1);
606         
607         key= ob_get_key(ob);
608         ob->shapenr= BLI_countlist(&key->block);
609         
610         allspace(REMAKEIPO, 0);
611         allqueue(REDRAWIPO, 0);
612         allqueue(REDRAWACTION, 0);
613         allqueue(REDRAWNLA, 0);
614         allqueue(REDRAWBUTSOBJECT, 0);
615         allqueue(REDRAWBUTSEDIT, 0);
616 }
617
618 void delete_key(Object *ob)
619 {
620         KeyBlock *kb;
621         Key *key;
622         IpoCurve *icu;
623         
624         key= ob_get_key(ob);
625         if(key==NULL) return;
626         
627         kb= BLI_findlink(&key->block, ob->shapenr-1);
628
629         if(kb) {
630                 BLI_remlink(&key->block, kb);
631                 key->totkey--;
632                 if(key->refkey== kb) key->refkey= key->block.first;
633                         
634                 if(kb->data) MEM_freeN(kb->data);
635                 MEM_freeN(kb);
636                 
637                 for(kb= key->block.first; kb; kb= kb->next) {
638                         if(kb->adrcode>=ob->shapenr)
639                                 kb->adrcode--;
640                 }
641                 
642                 if(key->ipo) {
643                         
644                         for(icu= key->ipo->curve.first; icu; icu= icu->next) {
645                                 if(icu->adrcode==ob->shapenr-1) {
646                                         BLI_remlink(&key->ipo->curve, icu);
647                                         free_ipo_curve(icu);
648                                         break;
649                                 }
650                         }
651                         for(icu= key->ipo->curve.first; icu; icu= icu->next) 
652                                 if(icu->adrcode>=ob->shapenr)
653                                         icu->adrcode--;
654                 }               
655                 
656                 if(ob->shapenr>1) ob->shapenr--;
657         }
658         
659         if(key->totkey==0) {
660                 if(GS(key->from->name)==ID_ME) ((Mesh *)key->from)->key= NULL;
661                 else if(GS(key->from->name)==ID_CU) ((Curve *)key->from)->key= NULL;
662                 else if(GS(key->from->name)==ID_LT) ((Lattice *)key->from)->key= NULL;
663
664                 free_libblock_us(&(G.main->key), key);
665                 scrarea_queue_headredraw(curarea);      /* ipo remove too */
666         }
667         
668         DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
669         
670         allqueue(REDRAWVIEW3D, 0);
671         allqueue(REDRAWBUTSEDIT, 0);
672         allspace(REMAKEIPO, 0);
673         allqueue(REDRAWIPO, 0);
674 }
675
676 void move_keys(Object *ob)
677 {
678         Key *key;
679         KeyBlock *kb;
680         float div, dy, oldpos, vec[3], dvec[3];
681         int afbreek=0, firsttime= 1;
682         unsigned short event = 0;
683         short mval[2], val, xo, yo;
684         char str[32];
685         
686         if(G.sipo->blocktype!=ID_KE) return;
687         
688         if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
689         if(G.sipo->editipo==NULL) return;
690
691         key= ob_get_key(ob);
692         if(key==NULL) return;
693         
694         /* which kb is involved */
695         kb= BLI_findlink(&key->block, ob->shapenr-1);
696         if(kb==NULL) return;    
697         
698         oldpos= kb->pos;
699         
700         getmouseco_areawin(mval);
701         xo= mval[0];
702         yo= mval[1];
703         dvec[0]=dvec[1]=dvec[2]= 0.0; 
704
705         while(afbreek==0) {
706                 getmouseco_areawin(mval);
707                 if(mval[0]!=xo || mval[1]!=yo || firsttime) {
708                         firsttime= 0;
709                         
710                         dy= (float)(mval[1]- yo);
711
712                         div= (float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
713                         dvec[1]+= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/div;
714                         
715                         VECCOPY(vec, dvec);
716
717                         apply_keyb_grid(vec, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
718                         apply_keyb_grid(vec+1, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
719
720                         kb->pos= oldpos+vec[1];
721                         
722                         sprintf(str, "Y: %.3f  ", vec[1]);
723                         headerprint(str);
724                         
725                         xo= mval[0];
726                         yo= mval[1];
727                                 
728                         force_draw(0);
729                 }
730                 else BIF_wait_for_statechange();
731                 
732                 while(qtest()) {
733                         event= extern_qread(&val);
734                         if(val) {
735                                 switch(event) {
736                                 case ESCKEY:
737                                 case LEFTMOUSE:
738                                 case SPACEKEY:
739                                         afbreek= 1;
740                                         break;
741                                 default:
742                                         arrows_move_cursor(event);
743                                 }
744                         }
745                 }
746         }
747         
748         if(event==ESCKEY) {
749                 kb->pos= oldpos;
750         }
751         
752         sort_keys(key);
753         DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
754         
755         /* for boundbox */
756         editipo_changed(G.sipo, 0);
757
758         allspace(REMAKEIPO, 0);
759         allqueue(REDRAWIPO, 0);
760         allqueue(REDRAWVIEW3D, 0);
761         allqueue(REDRAWBUTSEDIT, 0);
762         scrarea_queue_redraw(curarea);
763 }