Pydrivers: Ipo Drivers controlled by Python expressions
[blender.git] / source / blender / src / drawipo.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 <stdio.h>
34 #include <math.h>
35 #include <string.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef _WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #endif   
46
47 #include "BMF_Api.h"
48 #include "MEM_guardedalloc.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_arithb.h"
52
53 #include "DNA_action_types.h"
54 #include "DNA_curve_types.h"
55 #include "DNA_ipo_types.h"
56 #include "DNA_key_types.h"
57 #include "DNA_object_types.h"
58 #include "DNA_scene_types.h"
59 #include "DNA_screen_types.h"
60 #include "DNA_space_types.h"
61 #include "DNA_sequence_types.h"
62 #include "DNA_userdef_types.h"
63
64 #include "BKE_curve.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_global.h"
67 #include "BKE_ipo.h"
68 #include "BKE_key.h"
69 #include "BKE_utildefines.h"
70
71 #include "BIF_gl.h"
72 #include "BIF_resources.h"
73 #include "BIF_screen.h"
74 #include "BIF_interface.h"
75 #include "BIF_mywindow.h"
76 #include "BIF_space.h"
77 #include "BIF_toolbox.h"
78 #include "BIF_glutil.h"
79 #include "BIF_editseq.h"
80
81 #include "BSE_drawipo.h"
82 #include "BSE_view.h"
83 #include "BSE_editipo.h"
84 #include "BSE_editipo_types.h"
85 #include "BSE_editnla_types.h"
86
87 #include "BPY_extern.h"
88
89 #include "mydevice.h"
90 #include "blendef.h"
91 #include "butspace.h"   // shouldnt be...
92
93 /* local define... also used in editipo ... */
94 #define ISPOIN(a, b, c)                       ( (a->b) && (a->c) )  
95 #define ISPOIN3(a, b, c, d)           ( (a->b) && (a->c) && (a->d) )
96 #define ISPOIN4(a, b, c, d, e)        ( (a->b) && (a->c) && (a->d) && (a->e) )   
97
98                 /* minimum pixels per gridstep */
99 #define IPOSTEP 35
100
101 static float ipogrid_dx, ipogrid_dy, ipogrid_startx, ipogrid_starty;
102 static int ipomachtx, ipomachty;
103
104 static int vertymin, vertymax, horxmin, horxmax;        /* globals to test LEFTMOUSE for scrollbar */
105
106 extern short ACTWIDTH;          /* this is ugly! */
107
108 static void scroll_prstr(float x, float y, float val, char dir, int disptype)
109 {
110         int len, macht;
111         char str[32];
112         
113         if(dir=='v') {
114                 macht= ipomachty;
115                 if ELEM(disptype, IPO_DISPDEGR, IPO_DISPTIME) {
116                         macht+=1;
117                         val *= 10;
118                 }
119         }
120         else macht= ipomachtx;
121         
122         if (macht<=0) sprintf(str, "%.*f", 1-macht, val);
123         else sprintf(str, "%d", (int)floor(val + 0.375));
124         
125         len= strlen(str);
126         if(dir=='h') x-= 4*len;
127         
128         if(dir=='v' && disptype==IPO_DISPDEGR) {
129                 str[len]= 186; /* Degree symbol */
130                 str[len+1]= 0;
131         }
132         
133         glRasterPos2f(x,  y);
134         BMF_DrawString(G.fonts, str);
135 }
136
137 static void step_to_grid(float *step, int *macht)
138 {
139         float loga, rem;
140         
141         /* try to write step as a power of 10 */
142         
143         loga= log10(*step);
144         *macht= (int)(loga);
145
146         rem= loga- *macht;
147         rem= pow(10.0, rem);
148         
149         if(loga<0.0) {
150                 if(rem < 0.2) rem= 0.2;
151                 else if(rem < 0.5) rem= 0.5;
152                 else rem= 1.0;
153
154                 *step= rem*pow(10.0, (float)*macht);
155                 
156                 // partial of a frame have no meaning
157                 switch(curarea->spacetype) {
158                 case SPACE_TIME: {
159                         SpaceTime *stime= curarea->spacedata.first;
160                         if(stime->flag & TIME_DRAWFRAMES) {
161                                 rem = 1.0;
162                                 *step = 1.0;
163                         }
164                         break;
165                 }
166                 case SPACE_SEQ: {
167                         SpaceTime * sseq= curarea->spacedata.first;
168                         if (sseq->flag & SEQ_DRAWFRAMES) {
169                                 rem = 1.0;
170                                 *step = 1.0;
171                         }
172                 }
173                 default:
174                         break;
175                 }
176
177                 
178                 
179                 if(rem==1.0) (*macht)++;        // prevents printing 1.0 2.0 3.0 etc
180         }
181         else {
182                 if(rem < 2.0) rem= 2.0;
183                 else if(rem < 5.0) rem= 5.0;
184                 else rem= 10.0;
185                 
186                 *step= rem*pow(10.0, (float)*macht);
187                 
188                 (*macht)++;
189                 if(rem==10.0) (*macht)++;       // prevents printing 1.0 2.0 3.0 etc
190         }
191 }
192
193 void calc_ipogrid()
194 {
195         float space, pixels, secondiv=1.0;
196         int secondgrid= 0;
197         /* rule: gridstep is minimal IPOSTEP pixels */
198         /* how large is IPOSTEP pixels? */
199         
200         if(G.v2d==0) return;
201         
202         /* detect of we have seconds or frames, should become argument */
203
204         switch(curarea->spacetype) {
205         case SPACE_TIME: {
206                 SpaceTime *stime= curarea->spacedata.first;
207                 if(!(stime->flag & TIME_DRAWFRAMES)) {
208                         secondgrid= 1;
209                         secondiv= 0.01 * (float)G.scene->r.frs_sec;
210                 }
211                 break;
212         }
213         case SPACE_SEQ: {
214                 SpaceSeq * sseq = curarea->spacedata.first;
215                 if (!(sseq->flag & SEQ_DRAWFRAMES)) {
216                         secondgrid = 1;
217                         secondiv = 0.01 * (float)G.scene->r.frs_sec;
218                 }
219         }
220         default:
221                 break;
222         }
223         
224         space= G.v2d->cur.xmax - G.v2d->cur.xmin;
225         pixels= G.v2d->mask.xmax-G.v2d->mask.xmin;
226         
227         ipogrid_dx= IPOSTEP*space/(secondiv*pixels);
228         step_to_grid(&ipogrid_dx, &ipomachtx);
229         ipogrid_dx*= secondiv;
230         
231         if ELEM3(curarea->spacetype, SPACE_SEQ, SPACE_SOUND, SPACE_TIME) {
232                 if(ipogrid_dx < 0.1) ipogrid_dx= 0.1;
233                 ipomachtx-= 2;
234                 if(ipomachtx<-2) ipomachtx= -2;
235         }
236         
237         space= (G.v2d->cur.ymax - G.v2d->cur.ymin);
238         pixels= curarea->winy;
239         ipogrid_dy= IPOSTEP*space/pixels;
240         step_to_grid(&ipogrid_dy, &ipomachty);
241         
242         if ELEM3(curarea->spacetype, SPACE_SEQ, SPACE_SOUND, SPACE_TIME) {
243                 if(ipogrid_dy < 1.0) ipogrid_dy= 1.0;
244                 if(ipomachty<1) ipomachty= 1;
245         }
246         
247         ipogrid_startx= secondiv*(G.v2d->cur.xmin/secondiv - fmod(G.v2d->cur.xmin/secondiv, ipogrid_dx/secondiv));
248         if(G.v2d->cur.xmin<0.0) ipogrid_startx-= ipogrid_dx;
249         
250         ipogrid_starty= (G.v2d->cur.ymin-fmod(G.v2d->cur.ymin, ipogrid_dy));
251         if(G.v2d->cur.ymin<0.0) ipogrid_starty-= ipogrid_dy;
252         
253 }
254
255 void draw_ipogrid(void)
256 {
257         float vec1[2], vec2[2];
258         int a, step;
259         
260         vec1[0]= vec2[0]= ipogrid_startx;
261         vec1[1]= ipogrid_starty;
262         vec2[1]= G.v2d->cur.ymax;
263         
264         step= (G.v2d->mask.xmax-G.v2d->mask.xmin+1)/IPOSTEP;
265         
266         BIF_ThemeColor(TH_GRID);
267         
268         for(a=0; a<step; a++) {
269                 glBegin(GL_LINE_STRIP);
270                 glVertex2fv(vec1); glVertex2fv(vec2);
271                 glEnd();
272                 vec2[0]= vec1[0]+= ipogrid_dx;
273         }
274         
275         vec2[0]= vec1[0]-= 0.5*ipogrid_dx;
276         
277         BIF_ThemeColorShade(TH_GRID, 16);
278         
279         step++;
280         for(a=0; a<=step; a++) {
281                 glBegin(GL_LINE_STRIP);
282                 glVertex2fv(vec1); glVertex2fv(vec2);
283                 glEnd();
284                 vec2[0]= vec1[0]-= ipogrid_dx;
285         }
286         
287         if ELEM4(curarea->spacetype, SPACE_SOUND, SPACE_ACTION, SPACE_NLA, SPACE_TIME);
288         else {
289                 vec1[0]= ipogrid_startx;
290                 vec1[1]= vec2[1]= ipogrid_starty;
291                 vec2[0]= G.v2d->cur.xmax;
292                 
293                 step= (curarea->winy+1)/IPOSTEP;
294                 
295                 BIF_ThemeColor(TH_GRID);
296                 for(a=0; a<=step; a++) {
297                         glBegin(GL_LINE_STRIP);
298                         glVertex2fv(vec1); glVertex2fv(vec2);
299                         glEnd();
300                         vec2[1]= vec1[1]+= ipogrid_dy;
301                 }
302                 vec2[1]= vec1[1]-= 0.5*ipogrid_dy;
303                 step++;
304                 
305                 if(curarea->spacetype==SPACE_IPO) {
306                         BIF_ThemeColorShade(TH_GRID, 16);
307                         for(a=0; a<step; a++) {
308                                 glBegin(GL_LINE_STRIP);
309                                 glVertex2fv(vec1); glVertex2fv(vec2);
310                                 glEnd();
311                                 vec2[1]= vec1[1]-= ipogrid_dy;
312                         }
313                 }
314         }
315         
316         BIF_ThemeColorShade(TH_GRID, -50);
317         
318         if (curarea->spacetype!=SPACE_ACTION && curarea->spacetype!=SPACE_NLA)
319         {       /* Horizontal axis */
320                 vec1[0]= G.v2d->cur.xmin;
321                 vec2[0]= G.v2d->cur.xmax;
322                 vec1[1]= vec2[1]= 0.0;
323                 glBegin(GL_LINE_STRIP);
324                 
325                 glVertex2fv(vec1);
326                 glVertex2fv(vec2);
327                 
328                 glEnd();
329         }
330         
331         /* Vertical axis */
332         
333         vec1[1]= G.v2d->cur.ymin;
334         vec2[1]= G.v2d->cur.ymax;
335         vec1[0]= vec2[0]= 0.0;
336         glBegin(GL_LINE_STRIP);
337         glVertex2fv(vec1); glVertex2fv(vec2);
338         glEnd();
339         
340         /* Limits box */
341         if(curarea->spacetype==SPACE_IPO) {
342                 if(G.sipo->blocktype==ID_SEQ) {
343                         Sequence * last_seq = get_last_seq();
344                         float start = 0.0;
345                         float end = 100.0;
346
347                         if (last_seq && 
348                             ((last_seq->flag & SEQ_IPO_FRAME_LOCKED) != 0)) {
349                                 start = last_seq->startdisp;
350                                 end = last_seq->enddisp;
351                         }
352
353                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
354                         glRectf(start,  0.0,  end,  1.0); 
355                         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
356                 }
357                 else if(ELEM(G.sipo->blocktype, ID_CU, ID_CO)) {
358                         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
359                         glRectf(0.0,  1.0,  G.v2d->cur.xmax,  1.0); 
360                         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
361                 }
362         }
363 }
364
365 void areamouseco_to_ipoco(View2D *v2d, short *mval, float *x, float *y)
366 {
367         float div, ofs;
368         
369         div= v2d->mask.xmax-v2d->mask.xmin;
370         ofs= v2d->mask.xmin;
371         
372         *x= v2d->cur.xmin+ (v2d->cur.xmax-v2d->cur.xmin)*(mval[0]-ofs)/div;
373         
374         div= v2d->mask.ymax-v2d->mask.ymin;
375         ofs= v2d->mask.ymin;
376         
377         *y= v2d->cur.ymin+ (v2d->cur.ymax-v2d->cur.ymin)*(mval[1]-ofs)/div;
378 }
379
380 void ipoco_to_areaco(View2D *v2d, float *vec, short *mval)
381 {
382         float x, y;
383         
384         mval[0]= IS_CLIPPED;
385         
386         x= (vec[0] - v2d->cur.xmin)/(v2d->cur.xmax-v2d->cur.xmin);
387         y= (vec[1] - v2d->cur.ymin)/(v2d->cur.ymax-v2d->cur.ymin);
388
389         if(x>=0.0 && x<=1.0) {
390                 if(y>=0.0 && y<=1.0) {
391                         mval[0]= v2d->mask.xmin + x*(v2d->mask.xmax-v2d->mask.xmin);
392                         mval[1]= v2d->mask.ymin + y*(v2d->mask.ymax-v2d->mask.ymin);
393                 }
394         }
395 }
396
397 void ipoco_to_areaco_noclip(View2D *v2d, float *vec, short *mval)
398 {
399         float x, y;
400         
401         x= (vec[0] - v2d->cur.xmin)/(v2d->cur.xmax-v2d->cur.xmin);
402         y= (vec[1] - v2d->cur.ymin)/(v2d->cur.ymax-v2d->cur.ymin);
403         
404         x= v2d->mask.xmin + x*(v2d->mask.xmax-v2d->mask.xmin);
405         y= v2d->mask.ymin + y*(v2d->mask.ymax-v2d->mask.ymin);
406         
407         if(x<-32760) mval[0]= -32760;
408         else if(x>32760) mval[0]= 32760;
409         else mval[0]= x;
410         
411         if(y<-32760) mval[1]= -32760;
412         else if(y>32760) mval[1]= 32760;
413         else mval[1]= y;
414 }
415
416 int in_ipo_buttons(void)
417 {
418         short mval[2];
419         
420         getmouseco_areawin(mval);
421         
422         if(mval[0]< G.v2d->mask.xmax) return 0;
423         else return 1;
424 }
425
426 static View2D *spacelink_get_view2d(SpaceLink *sl)
427 {
428         if(sl->spacetype==SPACE_IPO) 
429                 return &((SpaceIpo *)sl)->v2d;
430         else if(sl->spacetype==SPACE_SOUND) 
431                 return &((SpaceSound *)sl)->v2d;
432         if(sl->spacetype==SPACE_ACTION) 
433                 return &((SpaceAction *)sl)->v2d;
434         if(sl->spacetype==SPACE_NLA) 
435                 return &((SpaceNla *)sl)->v2d;
436         if(sl->spacetype==SPACE_TIME) 
437                 return &((SpaceTime *)sl)->v2d;
438         if(sl->spacetype==SPACE_SEQ)
439                 return &((SpaceSeq *)sl)->v2d;
440         return NULL;
441 }
442
443 /* copies changes in this view from or to all 2d views with lock option open */
444 void view2d_do_locks(ScrArea *cursa, int flag)
445 {
446         ScrArea *sa;
447         View2D *v2d, *curv2d;
448         SpaceLink *sl;
449         
450         curv2d= spacelink_get_view2d(cursa->spacedata.first);
451         if(curv2d==NULL) return;
452         if((curv2d->flag & V2D_VIEWLOCK)==0) return;
453
454         for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
455                 if(sa!=cursa) {
456                         for(sl= sa->spacedata.first; sl; sl= sl->next) {
457                                 
458                                 v2d= spacelink_get_view2d(sl);
459                                 if(v2d) {
460                                         if(v2d->flag & V2D_VIEWLOCK) {
461                                                 if(flag & V2D_LOCK_COPY) {
462                                                         v2d->cur.xmin= curv2d->cur.xmin;
463                                                         v2d->cur.xmax= curv2d->cur.xmax;
464                                                 }
465                                                 else {
466                                                         curv2d->cur.xmin= v2d->cur.xmin;
467                                                         curv2d->cur.xmax= v2d->cur.xmax;
468                                                         scrarea_queue_winredraw(sa);
469                                                 }
470                                                 
471                                                 if(flag & V2D_LOCK_REDRAW)
472                                                         scrarea_do_windraw(sa);
473                                                 else
474                                                         scrarea_queue_winredraw(sa);
475                                         }
476                                 }
477                         }
478                 }
479         }
480 }
481
482 /* event based, note: curarea is in here... */
483 void view2d_zoom(View2D *v2d, float factor, int winx, int winy) 
484 {
485         float dx= factor*(v2d->cur.xmax-v2d->cur.xmin);
486         float dy= factor*(v2d->cur.ymax-v2d->cur.ymin);
487         if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) {
488                 v2d->cur.xmin+= dx;
489                 v2d->cur.xmax-= dx;
490         }
491         if ((v2d->keepzoom & V2D_LOCKZOOM_Y)==0) {
492                 v2d->cur.ymin+= dy;
493                 v2d->cur.ymax-= dy;
494         }
495         test_view2d(v2d, winx, winy);
496         view2d_do_locks(curarea, V2D_LOCK_COPY);
497 }
498
499
500 void test_view2d(View2D *v2d, int winx, int winy)
501 {
502         /* cur is not allowed to be larger than max, smaller than min, or outside of tot */
503         rctf *cur, *tot;
504         float dx, dy, temp, fac, zoom;
505         
506         /* correct winx for scroll */
507         if(v2d->scroll & L_SCROLL) winx-= SCROLLB;
508         if(v2d->scroll & B_SCROLL) winy-= SCROLLH;
509         
510         /* header completely closed window */
511         if(winy<=0) return;
512         
513         cur= &v2d->cur;
514         tot= &v2d->tot;
515         
516         dx= cur->xmax-cur->xmin;
517         dy= cur->ymax-cur->ymin;
518
519         /* Reevan's test */
520         if (v2d->keepzoom & V2D_LOCKZOOM_Y)
521                 v2d->cur.ymax=v2d->cur.ymin+((float)winy);
522
523         if (v2d->keepzoom & V2D_LOCKZOOM_X)
524                 v2d->cur.xmax=v2d->cur.xmin+((float)winx);
525
526         if(v2d->keepzoom) {
527                 
528                 zoom= ((float)winx)/dx;
529                 
530                 if(zoom<v2d->minzoom || zoom>v2d->maxzoom) {
531                         if(zoom<v2d->minzoom) fac= zoom/v2d->minzoom;
532                         else fac= zoom/v2d->maxzoom;
533                         
534                         dx*= fac;
535                         temp= 0.5*(cur->xmax+cur->xmin);
536                         
537                         cur->xmin= temp-0.5*dx;
538                         cur->xmax= temp+0.5*dx;
539                 }
540                 
541                 zoom= ((float)winy)/dy;
542                 
543                 if(zoom<v2d->minzoom || zoom>v2d->maxzoom) {
544                         if(zoom<v2d->minzoom) fac= zoom/v2d->minzoom;
545                         else fac= zoom/v2d->maxzoom;
546                         
547                         dy*= fac;
548                         temp= 0.5*(cur->ymax+cur->ymin);
549                         cur->ymin= temp-0.5*dy;
550                         cur->ymax= temp+0.5*dy;
551                 }
552         }
553         else {
554                 if(dx<G.v2d->min[0]) {
555                         dx= G.v2d->min[0];
556                         temp= 0.5*(cur->xmax+cur->xmin);
557                         cur->xmin= temp-0.5*dx;
558                         cur->xmax= temp+0.5*dx;
559                 }
560                 else if(dx>G.v2d->max[0]) {
561                         dx= G.v2d->max[0];
562                         temp= 0.5*(cur->xmax+cur->xmin);
563                         cur->xmin= temp-0.5*dx;
564                         cur->xmax= temp+0.5*dx;
565                 }
566                 
567                 if(dy<G.v2d->min[1]) {
568                         dy= G.v2d->min[1];
569                         temp= 0.5*(cur->ymax+cur->ymin);
570                         cur->ymin= temp-0.5*dy;
571                         cur->ymax= temp+0.5*dy;
572                 }
573                 else if(dy>G.v2d->max[1]) {
574                         dy= G.v2d->max[1];
575                         temp= 0.5*(cur->ymax+cur->ymin);
576                         cur->ymin= temp-0.5*dy;
577                         cur->ymax= temp+0.5*dy;
578                 }
579         }
580
581         if(v2d->keepaspect) {
582                 short do_x=0, do_y=0;
583                 
584                 /* when a window edge changes, the aspect ratio can't be used to
585                    find which is the best new 'cur' rect. thats why it stores 'old' */
586                 if(winx!=v2d->oldwinx) do_x= 1;
587                 if(winy!=v2d->oldwiny) do_y= 1;
588                 
589                 dx= (cur->ymax-cur->ymin)/(cur->xmax-cur->xmin);
590                 dy= ((float)winy)/((float)winx);
591                 
592                 if(do_x==do_y) {        // both sizes change, ctrl+uparrow
593                         if(do_x==1 && do_y==1) {
594                                 if( ABS(winx-v2d->oldwinx)>ABS(winy-v2d->oldwiny)) do_y= 0;
595                                 else do_x= 0;
596                         }
597                         else if( dy > 1.0) do_x= 0; else do_x= 1;
598                 }
599                 
600                 v2d->oldwinx= winx; 
601                 v2d->oldwiny= winy;
602                 
603                 if( do_x ) {
604                         
605                         /* portrait window: correct for x */
606                         dx= cur->ymax-cur->ymin;
607                         temp= (cur->xmax+cur->xmin);
608                         
609                         cur->xmin= temp/2.0 - 0.5*dx/dy;
610                         cur->xmax= temp/2.0 + 0.5*dx/dy;
611                 }
612                 else {
613                         dx= cur->xmax-cur->xmin;
614                         temp= (cur->ymax+cur->ymin);
615                         
616                         cur->ymin= temp/2.0 - 0.5*dy*dx;
617                         cur->ymax= temp/2.0 + 0.5*dy*dx;
618                 }
619         }
620         
621         if(v2d->keeptot) {
622                 dx= cur->xmax-cur->xmin;
623                 dy= cur->ymax-cur->ymin;
624                 
625                 if(dx > tot->xmax-tot->xmin) {
626                         if(v2d->keepzoom==0) {
627                                 if(cur->xmin<tot->xmin) cur->xmin= tot->xmin;
628                                 if(cur->xmax>tot->xmax) cur->xmax= tot->xmax;
629                         }
630                         else {
631                                 if(cur->xmax < tot->xmax) {
632                                         dx= tot->xmax-cur->xmax;
633                                         cur->xmin+= dx;
634                                         cur->xmax+= dx;
635                                 }
636                                 else if(cur->xmin > tot->xmin) {
637                                         dx= cur->xmin-tot->xmin;
638                                         cur->xmin-= dx;
639                                         cur->xmax-= dx;
640                                 }
641                         }
642                 }
643                 else {
644                         if(cur->xmin < tot->xmin) {
645                                 dx= tot->xmin-cur->xmin;
646                                 cur->xmin+= dx;
647                                 cur->xmax+= dx;
648                         }
649                         else if(cur->xmax > tot->xmax) {
650                                 dx= cur->xmax-tot->xmax;
651                                 cur->xmin-= dx;
652                                 cur->xmax-= dx;
653                         }
654                 }
655                 
656                 if(dy > tot->ymax-tot->ymin) {
657                         if(v2d->keepzoom==0) {
658                                 if(cur->ymin<tot->ymin) cur->ymin= tot->ymin;
659                                 if(cur->ymax>tot->ymax) cur->ymax= tot->ymax;
660                         }
661                         else {
662                                 if(cur->ymax < tot->ymax) {
663                                         dy= tot->ymax-cur->ymax;
664                                         cur->ymin+= dy;
665                                         cur->ymax+= dy;
666                                 }
667                                 else if(cur->ymin > tot->ymin) {
668                                         dy= cur->ymin-tot->ymin;
669                                         cur->ymin-= dy;
670                                         cur->ymax-= dy;
671                                 }
672                         }
673                 }
674                 else {
675                         if(cur->ymin < tot->ymin) {
676                                 dy= tot->ymin-cur->ymin;
677                                 cur->ymin+= dy;
678                                 cur->ymax+= dy;
679                         }
680                         else if(cur->ymax > tot->ymax) {
681                                 dy= cur->ymax-tot->ymax;
682                                 cur->ymin-= dy;
683                                 cur->ymax-= dy;
684                         }
685                 }
686         }
687 }
688
689 #define IPOBUTX 65
690 static int calc_ipobuttonswidth(ScrArea *sa)
691 {
692         SpaceIpo *sipo= sa->spacedata.first;
693         EditIpo *ei;
694         int ipowidth = IPOBUTX;
695         int a;
696         
697         /* default width when no space ipo or no channels */
698         if (sipo == NULL) return IPOBUTX;
699         if ((sipo->totipo==0) || (sipo->editipo==NULL)) return IPOBUTX;
700
701         ei= sipo->editipo;
702         
703         for(a=0; a<sipo->totipo; a++, ei++) {
704                 if (BMF_GetStringWidth(G.font, ei->name) + 18 > ipowidth) 
705                         ipowidth = BMF_GetStringWidth(G.font, ei->name) + 18;
706         }
707         return ipowidth;
708
709 }
710
711 void calc_scrollrcts(ScrArea *sa, View2D *v2d, int winx, int winy)
712 {
713         v2d->mask.xmin= v2d->mask.ymin= 0;
714         v2d->mask.xmax= winx;
715         v2d->mask.ymax= winy;
716         
717         if(sa->spacetype==SPACE_ACTION) {
718                 if(sa->winx > ACTWIDTH+50) { 
719                         v2d->mask.xmin+= ACTWIDTH;
720                         v2d->hor.xmin+=ACTWIDTH;
721                 }
722         }
723         else if(sa->spacetype==SPACE_NLA){
724                 if(sa->winx > NLAWIDTH+50) { 
725                         v2d->mask.xmin+= NLAWIDTH;
726                         v2d->hor.xmin+=NLAWIDTH;
727                 }
728         }
729         else if(sa->spacetype==SPACE_IPO) {
730                 int ipobutx = calc_ipobuttonswidth(sa);
731                 
732                 v2d->mask.xmax-= ipobutx;
733                 
734                 if(v2d->mask.xmax<ipobutx)
735                         v2d->mask.xmax= winx;
736         }
737         
738         if(v2d->scroll) {
739                 if(v2d->scroll & L_SCROLL) {
740                         v2d->vert= v2d->mask;
741                         v2d->vert.xmax= SCROLLB;
742                         v2d->mask.xmin= SCROLLB;
743                 }
744                 else if(v2d->scroll & R_SCROLL) {
745                         v2d->vert= v2d->mask;
746                         v2d->vert.xmin= v2d->vert.xmax-SCROLLB;
747                         v2d->mask.xmax= v2d->vert.xmin;
748                 }
749                 
750                 if(v2d->scroll & B_SCROLL) {
751                         v2d->hor= v2d->mask;
752                         v2d->hor.ymax= SCROLLH;
753                         v2d->mask.ymin= SCROLLH;
754                 }
755                 else if(v2d->scroll & T_SCROLL) {
756                         v2d->hor= v2d->mask;
757                         v2d->hor.ymin= v2d->hor.ymax-SCROLLH;
758                         v2d->mask.ymax= v2d->hor.ymin;
759                 }
760         }
761 }
762
763         /* draws a line in left vertical scrollbar at the given height */
764 static void draw_solution_line(View2D *v2d, float h)
765 {
766         float vec[2];
767         short mval[2];
768
769         vec[0]= v2d->cur.xmin;
770         vec[1]= h;
771         ipoco_to_areaco(v2d, vec, mval);
772         if(mval[0]!=IS_CLIPPED) {
773                 glBegin(GL_LINES);
774                 glVertex2f(v2d->vert.xmin, mval[1]);
775                 glVertex2f(v2d->vert.xmax, mval[1]);
776                 glEnd();
777         }
778 }
779
780 static void draw_solution(SpaceIpo *sipo)
781 {
782         View2D *v2d= &sipo->v2d;
783         EditIpo *ei;
784         int a;
785
786         if (!(v2d->scroll & VERT_SCROLL)) return;
787
788         ei= sipo->editipo;
789         for(a=0; a<sipo->totipo; a++, ei++) {
790                 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
791                         cpack(ei->col);
792                                 
793                                 /* DISPBITS ipos have 'multiple' values. */
794                         if(ei->disptype==IPO_DISPBITS) {
795                                 int b, val= ei->icu->curval;
796                                         
797                                 for (b=0; b<31; b++)
798                                         if (val & (1<<b))
799                                                 draw_solution_line(v2d, b+1);
800                         } else {
801                                 draw_solution_line(v2d, ei->icu->curval);
802                         }
803                 }
804         }
805 }
806
807 /* used for drawing timeline */
808 void draw_view2d_numbers_horiz(int drawframes)
809 {
810         float fac, fac2, dfac, val;
811         
812         /* the numbers: convert ipogrid_startx and -dx to scroll coordinates */
813         
814         fac= (ipogrid_startx- G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
815         fac= G.v2d->mask.xmin+fac*(G.v2d->mask.xmax-G.v2d->mask.xmin);
816         
817         dfac= (ipogrid_dx)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
818         dfac= dfac*(G.v2d->mask.xmax-G.v2d->mask.xmin);
819         
820         BIF_ThemeColor(TH_TEXT);
821         val= ipogrid_startx;
822         while(fac < G.v2d->mask.xmax) {
823                 
824                 if(drawframes) {
825                         ipomachtx= 1;
826                         scroll_prstr(fac, 2.0+(float)(G.v2d->mask.ymin), val, 'h', 0);
827                 }
828                 else {
829                         fac2= val/(float)G.scene->r.frs_sec;
830                         scroll_prstr(fac, 2.0+(float)(G.v2d->mask.ymin), fac2, 'h', 0);
831                 }
832                 
833                 fac+= dfac;
834                 val+= ipogrid_dx;
835         }
836 }
837
838
839 void drawscroll(int disptype)
840 {
841         rcti vert, hor;
842         float fac, dfac, val, fac2, tim;
843         int darker, dark, light, lighter;
844         
845         vert= (G.v2d->vert);
846         hor= (G.v2d->hor);
847         
848         darker= -40;
849         dark= 0;
850         light= 20;
851         lighter= 50;
852         
853         if(G.v2d->scroll & HOR_SCROLL) {
854                 
855                 BIF_ThemeColorShade(TH_SHADE1, light);
856                 glRecti(hor.xmin,  hor.ymin,  hor.xmax,  hor.ymax);
857                 
858                 /* slider */
859                 fac= (G.v2d->cur.xmin- G.v2d->tot.xmin)/(G.v2d->tot.xmax-G.v2d->tot.xmin);
860                 if(fac<0.0) fac= 0.0;
861                 horxmin= hor.xmin+fac*(hor.xmax-hor.xmin);
862                 
863                 fac= (G.v2d->cur.xmax- G.v2d->tot.xmin)/(G.v2d->tot.xmax-G.v2d->tot.xmin);
864                 if(fac>1.0) fac= 1.0;
865                 horxmax= hor.xmin+fac*(hor.xmax-hor.xmin);
866                 
867                 if(horxmin > horxmax) horxmin= horxmax;
868                 
869                 BIF_ThemeColorShade(TH_SHADE1, dark);
870                 glRecti(horxmin,  hor.ymin,  horxmax,  hor.ymax);
871
872                 /* decoration bright line */
873                 BIF_ThemeColorShade(TH_SHADE1, lighter);
874                 sdrawline(hor.xmin, hor.ymax, hor.xmax, hor.ymax);
875
876                 /* the numbers: convert ipogrid_startx and -dx to scroll coordinates */
877                 fac= (ipogrid_startx- G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
878                 fac= hor.xmin+fac*(hor.xmax-hor.xmin);
879                 
880                 dfac= (ipogrid_dx)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
881                 dfac= dfac*(hor.xmax-hor.xmin);
882                 
883                 BIF_ThemeColor(TH_TEXT);
884                 val= ipogrid_startx;
885                 while(fac < hor.xmax) {
886                         
887                         if(curarea->spacetype==SPACE_OOPS);
888                         else if(curarea->spacetype==SPACE_SEQ) {
889                                 SpaceSeq * sseq = curarea->spacedata.first;
890                                 if (sseq->flag & SEQ_DRAWFRAMES) {
891                                         ipomachtx = 1;
892                                         scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
893                                 } else {
894                                         fac2= val/(float)G.scene->r.frs_sec;
895                                         tim= floor(fac2);
896                                         fac2= fac2-tim;
897                                         scroll_prstr(fac, 3.0+(float)(hor.ymin), tim+G.scene->r.frs_sec*fac2/100.0, 'h', disptype);
898                                 }
899                         }
900                         else if (curarea->spacetype==SPACE_SOUND) {
901                                 SpaceSound *ssound= curarea->spacedata.first;
902                                 
903                                 if(ssound->flag & SND_DRAWFRAMES) {
904                                         ipomachtx= 1;
905                                         scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
906                                 }
907                                 else {
908                                         fac2= val/(float)G.scene->r.frs_sec;
909                                         scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
910                                 }
911                         }
912                         else if (curarea->spacetype==SPACE_TIME) {
913                                 SpaceTime *stime= curarea->spacedata.first;
914                                 
915                                 if(stime->flag & TIME_DRAWFRAMES) {
916                                         ipomachtx= 1;
917                                         scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
918                                 }
919                                 else {
920                                         fac2= val/(float)G.scene->r.frs_sec;
921                                         scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
922                                 }
923                         }
924                         else if (curarea->spacetype==SPACE_IPO) {
925                                 EditIpo *ei= get_active_editipo();
926                                 
927                                 if(ei && ei->icu && ei->icu->driver) {
928                                         int adrcode= ei->icu->driver->adrcode;
929                                         
930                                         if(adrcode==OB_ROT_X || adrcode==OB_ROT_Y || adrcode==OB_ROT_Z) {
931                                                 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'v', IPO_DISPDEGR);
932                                         }
933                                         else 
934                                                 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
935                                 }
936                                 else 
937                                         scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
938                         }
939                         else {
940                                 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
941                         }
942                         
943                         fac+= dfac;
944                         val+= ipogrid_dx;
945                 }
946         }
947         
948         if(G.v2d->scroll & VERT_SCROLL) {
949                 BIF_ThemeColorShade(TH_SHADE1, light);
950                 glRecti(vert.xmin,  vert.ymin,  vert.xmax,  vert.ymax);
951                 
952                 /* slider */
953                 fac= (G.v2d->cur.ymin- G.v2d->tot.ymin)/(G.v2d->tot.ymax-G.v2d->tot.ymin);
954                 if(fac<0.0) fac= 0.0;
955                 vertymin= vert.ymin+fac*(vert.ymax-vert.ymin);
956                 
957                 fac= (G.v2d->cur.ymax- G.v2d->tot.ymin)/(G.v2d->tot.ymax-G.v2d->tot.ymin);
958                 if(fac>1.0) fac= 1.0;
959                 vertymax= vert.ymin+fac*(vert.ymax-vert.ymin);
960                 
961                 if(vertymin > vertymax) vertymin= vertymax;
962                 
963                 BIF_ThemeColorShade(TH_SHADE1, dark);
964                 glRecti(vert.xmin,  vertymin,  vert.xmax,  vertymax);
965
966                 /* decoration black line */
967                 BIF_ThemeColorShade(TH_SHADE1, darker);
968                 if(G.v2d->scroll & HOR_SCROLL) 
969                         sdrawline(vert.xmax, vert.ymin+SCROLLH, vert.xmax, vert.ymax);
970                 else 
971                         sdrawline(vert.xmax, vert.ymin, vert.xmax, vert.ymax);
972
973                 /* the numbers: convert ipogrid_starty and -dy to scroll coordinates */
974                 fac= (ipogrid_starty- G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
975                 fac= vert.ymin+SCROLLH+fac*(vert.ymax-vert.ymin-SCROLLH);
976                 
977                 dfac= (ipogrid_dy)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
978                 dfac= dfac*(vert.ymax-vert.ymin-SCROLLH);
979                 
980                 if(curarea->spacetype==SPACE_OOPS);
981                 else if(curarea->spacetype==SPACE_SEQ) {
982                         BIF_ThemeColor(TH_TEXT);
983                         val= ipogrid_starty;
984                         fac+= 0.5*dfac;
985                         while(fac < vert.ymax) {
986                                 scroll_prstr((float)(vert.xmax)-14.0, fac, val, 'v', disptype);
987                                 fac+= dfac;
988                                 val+= ipogrid_dy;
989                         }
990                 }
991                 else if (curarea->spacetype==SPACE_NLA){
992                 }
993                 else if (curarea->spacetype==SPACE_ACTION){
994                         /* No digits on vertical axis in action mode! */
995                 }
996                 else {
997                         BIF_ThemeColor(TH_TEXT);
998                         val= ipogrid_starty;
999                         while(fac < vert.ymax) {
1000                                 scroll_prstr((float)(vert.xmax)-14.0, fac, val, 'v', disptype);
1001                                 fac+= dfac;
1002                                 val+= ipogrid_dy;
1003                         }
1004                 }
1005         }
1006 }
1007
1008 static void draw_ipobuts(SpaceIpo *sipo)
1009 {
1010         ScrArea *area= sipo->area;
1011         View2D *v2d= &sipo->v2d;
1012         Object *ob= OBACT;
1013         uiBlock *block;
1014         uiBut *but;
1015         EditIpo *ei;
1016         int a, y, sel, tot, ipobutx;
1017         char naam[20];
1018         
1019         if(area->winx< calc_ipobuttonswidth(area)) return;
1020         
1021         if(sipo->butofs) {
1022                 tot= 30+IPOBUTY*sipo->totipo;
1023                 if(tot<area->winy) sipo->butofs= 0;
1024         }
1025         
1026         ipobutx = calc_ipobuttonswidth(area);
1027         
1028         BIF_ThemeColor(TH_SHADE2);
1029         glRects(v2d->mask.xmax,  0,  area->winx,  area->winy);
1030         
1031         cpack(0x0);
1032         sdrawline(v2d->mask.xmax, 0, v2d->mask.xmax, area->winy);
1033
1034         if(sipo->totipo==0) return;
1035         if(sipo->editipo==0) return;
1036         
1037         sprintf(naam, "ipowin %d", area->win);
1038         block= uiNewBlock(&area->uiblocks, naam, UI_EMBOSSN, UI_HELV, area->win);
1039
1040         ei= sipo->editipo;
1041         y= area->winy-30+sipo->butofs;
1042         
1043         if(ob && sipo->blocktype==ID_KE) {
1044                 int icon;
1045                 if(ob->shapeflag & OB_SHAPE_LOCK) icon= ICON_PIN_HLT; else icon= ICON_PIN_DEHLT;
1046                 uiDefIconButBitC(block, TOG, OB_SHAPE_LOCK, B_SETKEY, icon, 
1047                                                  v2d->mask.xmax+18,y,25,20, &ob->shapeflag, 0, 0, 0, 0, "Always show the current Shape for this Object");
1048                 y-= IPOBUTY;
1049         }
1050         
1051         for(a=0; a<sipo->totipo; a++, ei++, y-=IPOBUTY) {
1052                 // this button defines visiblity, bit zero of flag (IPO_VISIBLE)
1053                 but= uiDefButBitS(block, TOG, IPO_VISIBLE, a+1, ei->name,  v2d->mask.xmax+18, y, ipobutx-15, IPOBUTY-1, &(ei->flag), 0, 0, 0, 0, "");
1054                 // no hilite, its not visible, but most of all the winmatrix is not correct later on...
1055                 uiButSetFlag(but, UI_TEXT_LEFT|UI_NO_HILITE);
1056                 
1057                 // this fake button defines selection of curves
1058                 if(ei->icu) {
1059                         cpack(ei->col);
1060                         
1061                         glRects(v2d->mask.xmax+8,  y+2,  v2d->mask.xmax+15, y+IPOBUTY-2);
1062                         sel= ei->flag & (IPO_SELECT + IPO_EDIT);
1063                         
1064                         uiEmboss((float)(v2d->mask.xmax+8), (float)(y+2), (float)(v2d->mask.xmax+15), (float)(y+IPOBUTY-2), sel);
1065                         
1066                         if(ei->icu->driver) {
1067                                 cpack(0x0);
1068                                 fdrawbox((float)v2d->mask.xmax+11,  (float)y+8,  (float)v2d->mask.xmax+12.5, (float)y+9.5);
1069                         }
1070                 }
1071                 
1072                 if(ei->flag & IPO_ACTIVE) {
1073                         cpack(0x0);
1074                         fdrawbox(v2d->mask.xmax+7,  y+1,  v2d->mask.xmax+16, y+IPOBUTY-1);
1075                 }
1076         }
1077         uiDrawBlock(block);
1078 }
1079
1080 static void draw_ipovertices(int sel)
1081 {
1082         EditIpo *ei;
1083         BezTriple *bezt;
1084         float v1[2];
1085         int val, ok, nr, a, b;
1086         
1087         if(G.f & G_PICKSEL) return;
1088         
1089         glPointSize(3.0);
1090         
1091         ei= G.sipo->editipo;
1092         for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
1093                 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
1094                         
1095                         if(G.sipo->showkey) {
1096                                 if(sel) BIF_ThemeColor(TH_TEXT_HI);
1097                                  else BIF_ThemeColor(TH_TEXT);
1098                         } else if(ei->flag & IPO_EDIT) {
1099                                 if(sel) BIF_ThemeColor(TH_VERTEX_SELECT); 
1100                                 else BIF_ThemeColor(TH_VERTEX);
1101                         } else {
1102                                 if(sel) BIF_ThemeColor(TH_TEXT_HI);
1103                                  else BIF_ThemeColor(TH_TEXT);
1104                                  
1105                                 val= (ei->icu->flag & IPO_SELECT)!=0;
1106                                 if(sel != val) continue;
1107                         }
1108
1109                         /* We can't change the color in the middle of
1110                          * GL_POINTS because then Blender will segfault
1111                          * on TNT2 / Linux with NVidia's drivers
1112                          * (at least up to ver. 4349) */                
1113                         
1114                         bglBegin(GL_POINTS);
1115                         
1116                         bezt= ei->icu->bezt;
1117                         a= ei->icu->totvert;
1118                         while(a--) {                            
1119                                 
1120                                 if(ei->disptype==IPO_DISPBITS) {
1121                                         ok= 0;
1122                                         if(ei->flag & IPO_EDIT) {
1123                                                 if( (bezt->f2 & 1) == sel ) ok= 1;
1124                                         }
1125                                         else ok= 1;
1126                                         
1127                                         if(ok) {
1128                                                 val= bezt->vec[1][1];
1129                                                 b= 0;
1130                                                 v1[0]= bezt->vec[1][0];
1131                                                 
1132                                                 while(b<31) {
1133                                                         if(val & (1<<b)) {      
1134                                                                 v1[1]= b+1;
1135                                                                 bglVertex3fv(v1);
1136                                                         }
1137                                                         b++;
1138                                                 }
1139                                         }
1140                                 }
1141                                 else {
1142                                         
1143                                         if(ei->flag & IPO_EDIT) {
1144                                                 if(ei->icu->ipo==IPO_BEZ) {
1145                                                         if( (bezt->f1 & 1) == sel )     
1146                                                                 bglVertex3fv(bezt->vec[0]);
1147                                                         if( (bezt->f3 & 1) == sel )     
1148                                                                 bglVertex3fv(bezt->vec[2]);
1149                                                 }
1150                                                 if( (bezt->f2 & 1) == sel )     
1151                                                         bglVertex3fv(bezt->vec[1]);
1152                                                 
1153                                         }
1154                                         else {
1155                                                 bglVertex3fv(bezt->vec[1]);
1156                                         }
1157                                 }
1158                                 
1159                                 bezt++;
1160                         }
1161
1162                         bglEnd();
1163                 }
1164         }
1165         
1166         glPointSize(1.0);
1167 }
1168
1169 static void draw_ipohandles(int sel)
1170 {
1171         extern unsigned int nurbcol[];
1172         EditIpo *ei;
1173         BezTriple *bezt;
1174         float *fp;
1175         unsigned int *col;
1176         int a, b;
1177         
1178         if(sel) col= nurbcol+4;
1179         else col= nurbcol;
1180         
1181         ei= G.sipo->editipo;
1182         for(a=0; a<G.sipo->totipo; a++, ei++) {
1183                 if ISPOIN4(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu, disptype!=IPO_DISPBITS) {
1184                         if(ei->icu->ipo==IPO_BEZ) {
1185                                 bezt= ei->icu->bezt;
1186                                 b= ei->icu->totvert;
1187                                 while(b--) {
1188                                         
1189                                         if( (bezt->f2 & 1)==sel) {
1190                                                 fp= bezt->vec[0];
1191                                                 cpack(col[bezt->h1]);
1192                                                 
1193                                                 glBegin(GL_LINE_STRIP); 
1194                                                 glVertex2fv(fp); glVertex2fv(fp+3); 
1195                                                 glEnd();
1196                                                 cpack(col[bezt->h2]);
1197                                                 
1198                                                 glBegin(GL_LINE_STRIP); 
1199                                                 glVertex2fv(fp+3); glVertex2fv(fp+6); 
1200                                                 glEnd();
1201                                         }
1202                                         else if( (bezt->f1 & 1)==sel) {
1203                                                 fp= bezt->vec[0];
1204                                                 cpack(col[bezt->h1]);
1205                                                 
1206                                                 glBegin(GL_LINE_STRIP); 
1207                                                 glVertex2fv(fp); glVertex2fv(fp+3); 
1208                                                 glEnd();
1209                                         }
1210                                         else if( (bezt->f3 & 1)==sel) {
1211                                                 fp= bezt->vec[1];
1212                                                 cpack(col[bezt->h2]);
1213                                                 
1214                                                 glBegin(GL_LINE_STRIP); 
1215                                                 glVertex2fv(fp); glVertex2fv(fp+3); 
1216                                                 glEnd();
1217                                         }
1218                                         
1219                                         bezt++;
1220                                 }
1221                         }
1222                 }
1223         }
1224 }
1225
1226 int pickselcode;
1227
1228 static void init_pickselcode(void)
1229 {
1230         pickselcode= 1;
1231 }
1232
1233 static void draw_ipocurves(int sel)
1234 {
1235         EditIpo *ei;
1236         IpoCurve *icu;
1237         BezTriple *bezt, *prevbezt;
1238         float *fp, fac, data[120], v1[2], v2[2], v3[2], v4[2];
1239         float cycdx=0, cycdy=0, cycxofs, cycyofs;
1240         int a, b, resol, cycount, val, nr;
1241         
1242         
1243         ei= G.sipo->editipo;
1244         for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
1245                 if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) {
1246                         
1247                         if(G.f & G_PICKSEL) {
1248                                 glLoadName(pickselcode++);
1249                                 val= 1;
1250                         }
1251                         else {
1252                                 val= (ei->flag & (IPO_SELECT+IPO_EDIT))!=0;
1253                                 val= (val==sel);
1254                         }
1255                         
1256                         if(val) {
1257                                 
1258                                 cycyofs= cycxofs= 0.0;
1259                                 cycount= 1;
1260                                 
1261                                 icu= ei->icu;   
1262                                 
1263                                 /* curve */
1264                                 if(G.sipo->showkey) BIF_ThemeColor(TH_TEXT); 
1265                                 else cpack(ei->col);
1266                                 
1267                                 /* cyclic */
1268                                 if(icu->extrap & IPO_CYCL) {
1269                                         cycdx= (icu->bezt+icu->totvert-1)->vec[1][0] - icu->bezt->vec[1][0];
1270                                         cycdy= (icu->bezt+icu->totvert-1)->vec[1][1] - icu->bezt->vec[1][1];
1271                                         if(cycdx>0.01) {
1272                                                 
1273                                                 while(icu->bezt->vec[1][0]+cycxofs > G.v2d->cur.xmin) {
1274                                                         cycxofs-= cycdx;
1275                                                         if(icu->extrap & IPO_DIR) cycyofs-= cycdy;
1276                                                         cycount++;
1277                                                 }
1278                                                 bezt= icu->bezt+(icu->totvert-1);
1279                                                 fac= 0.0;
1280                                                 while(bezt->vec[1][0]+fac < G.v2d->cur.xmax) {
1281                                                         cycount++;
1282                                                         fac+= cycdx;
1283                                                 }
1284                                         }
1285                                 }
1286                                 
1287                                 while(cycount--) {
1288                                         
1289                                         if(ei->disptype==IPO_DISPBITS) {
1290                                                 
1291                                                 /* lines */
1292                                                 cpack(ei->col);
1293                                                 bezt= icu->bezt;
1294                                                 a= icu->totvert;
1295                                                 
1296                                                 while(a--) {
1297                                                         val= bezt->vec[1][1];
1298                                                         b= 0;
1299                                                         
1300                                                         while(b<31) {
1301                                                                 if(val & (1<<b)) {
1302                                                                         v1[1]= b+1;
1303                                                                         
1304                                                                         glBegin(GL_LINE_STRIP);
1305                                                                         if(icu->extrap & IPO_CYCL) ;
1306                                                                         else if(a==icu->totvert-1) {
1307                                                                                 v1[0]= G.v2d->cur.xmin+cycxofs;
1308                                                                                 glVertex2fv(v1);
1309                                                                         }
1310                                                                         v1[0]= bezt->vec[1][0]+cycxofs;
1311                                                                         glVertex2fv(v1); 
1312                                                                         
1313                                                                         if(a) v1[0]= (bezt+1)->vec[1][0]+cycxofs;
1314                                                                         else if(icu->extrap & IPO_CYCL) ;
1315                                                                         else v1[0]= G.v2d->cur.xmax+cycxofs;
1316                                                                         
1317                                                                         glVertex2fv(v1);
1318                                                                         glEnd();
1319                                                                 }
1320                                                                 b++;
1321                                                         }
1322                                                         bezt++;
1323                                                 }
1324                                                 
1325                                         }
1326                                         else {
1327                                                 
1328                                                 b= icu->totvert-1;
1329                                                 prevbezt= icu->bezt;
1330                                                 bezt= prevbezt+1;
1331                                                 
1332                                                 glBegin(GL_LINE_STRIP);
1333                                                 
1334                                                 /* extrapolate to left? */
1335                                                 if( (icu->extrap & IPO_CYCL)==0) {
1336                                                         if(prevbezt->vec[1][0] > G.v2d->cur.xmin) {
1337                                                                 v1[0]= G.v2d->cur.xmin;
1338                                                                 if(icu->extrap==IPO_HORIZ || icu->ipo==IPO_CONST) v1[1]= prevbezt->vec[1][1];
1339                                                                 else {
1340                                                                         fac= (prevbezt->vec[0][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
1341                                                                         if(fac!=0.0) fac= 1.0/fac;
1342                                                                         v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[0][1]-prevbezt->vec[1][1]);
1343                                                                 }
1344                                                                 glVertex2fv(v1);
1345                                                         }
1346                                                 }
1347                                                 
1348                                                 if(b==0) {
1349                                                         v1[0]= prevbezt->vec[1][0]+cycxofs;
1350                                                         v1[1]= prevbezt->vec[1][1]+cycyofs;
1351                                                         glVertex2fv(v1);
1352                                                 }
1353                                                 
1354                                                 while(b--) {
1355                                                         if(icu->ipo==IPO_CONST) {
1356                                                                 v1[0]= prevbezt->vec[1][0]+cycxofs;
1357                                                                 v1[1]= prevbezt->vec[1][1]+cycyofs;
1358                                                                 glVertex2fv(v1);
1359                                                                 v1[0]= bezt->vec[1][0]+cycxofs;
1360                                                                 v1[1]= prevbezt->vec[1][1]+cycyofs;
1361                                                                 glVertex2fv(v1);
1362                                                         }
1363                                                         else if(icu->ipo==IPO_LIN) {
1364                                                                 v1[0]= prevbezt->vec[1][0]+cycxofs;
1365                                                                 v1[1]= prevbezt->vec[1][1]+cycyofs;
1366                                                                 glVertex2fv(v1);
1367                                                         }
1368                                                         else {
1369                                                                 /* resol not depending on horizontal resolution anymore, drivers for example... */
1370                                                                 if(icu->driver) resol= 32;
1371                                                                 else resol= 3.0*sqrt(bezt->vec[1][0] - prevbezt->vec[1][0]);
1372                                                                 
1373                                                                 if(resol<2) {
1374                                                                         v1[0]= prevbezt->vec[1][0]+cycxofs;
1375                                                                         v1[1]= prevbezt->vec[1][1]+cycyofs;
1376                                                                         glVertex2fv(v1);
1377                                                                 }
1378                                                                 else {
1379                                                                         if(resol>32) resol= 32;
1380                                                                         
1381                                                                         v1[0]= prevbezt->vec[1][0]+cycxofs;
1382                                                                         v1[1]= prevbezt->vec[1][1]+cycyofs;
1383                                                                         v2[0]= prevbezt->vec[2][0]+cycxofs;
1384                                                                         v2[1]= prevbezt->vec[2][1]+cycyofs;
1385                                                                         
1386                                                                         v3[0]= bezt->vec[0][0]+cycxofs;
1387                                                                         v3[1]= bezt->vec[0][1]+cycyofs;
1388                                                                         v4[0]= bezt->vec[1][0]+cycxofs;
1389                                                                         v4[1]= bezt->vec[1][1]+cycyofs;
1390                                                                         
1391                                                                         correct_bezpart(v1, v2, v3, v4);
1392                                                                         
1393                                                                         forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, 3);
1394                                                                         forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data+1, resol, 3);
1395                                                                         
1396                                                                         fp= data;
1397                                                                         while(resol--) {
1398                                                                                 glVertex2fv(fp);
1399                                                                                 fp+= 3;
1400                                                                         }
1401                                                                 }
1402                                                         }
1403                                                         prevbezt= bezt;
1404                                                         bezt++;
1405                                                         
1406                                                         /* last point? */
1407                                                         if(b==0) {
1408                                                                 v1[0]= prevbezt->vec[1][0]+cycxofs;
1409                                                                 v1[1]= prevbezt->vec[1][1]+cycyofs;
1410                                                                 glVertex2fv(v1);
1411                                                         }
1412                                                 }
1413                                                 
1414                                                 /* extrapolate to right? */
1415                                                 if( (icu->extrap & IPO_CYCL)==0) {
1416                                                         if(prevbezt->vec[1][0] < G.v2d->cur.xmax) {
1417                                                                 v1[0]= G.v2d->cur.xmax;
1418                                                                 if(icu->extrap==IPO_HORIZ || icu->ipo==IPO_CONST) v1[1]= prevbezt->vec[1][1];
1419                                                                 else {
1420                                                                         fac= (prevbezt->vec[2][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
1421                                                                         if(fac!=0.0) fac= 1.0/fac;
1422                                                                         v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[2][1]-prevbezt->vec[1][1]);
1423                                                                 }
1424                                                                 glVertex2fv(v1);
1425                                                         }
1426                                                 }
1427                                                 
1428                                                 glEnd();
1429                                                 
1430                                         }
1431                                         cycxofs+= cycdx;
1432                                         if(icu->extrap & IPO_DIR) cycyofs+= cycdy;
1433                                 }
1434                                 
1435                                 /* line that indicates the end of a speed curve */
1436                                 if(G.sipo->blocktype==ID_CU && icu->adrcode==CU_SPEED) {
1437                                         b= icu->totvert-1;
1438                                         if(b) {
1439                                                 glColor3ub(0, 0, 0);
1440                                                 bezt= icu->bezt+b;
1441                                                 glBegin(GL_LINES);
1442                                                 glVertex2f(bezt->vec[1][0], 0.0);
1443                                                 glVertex2f(bezt->vec[1][0], bezt->vec[1][1]);
1444                                                 glEnd();
1445                                         }
1446                                 }
1447                         }
1448                 }
1449         }
1450 }
1451
1452 static void draw_cfra(SpaceIpo *sipo)
1453 {
1454         View2D *v2d= &sipo->v2d;
1455         Object *ob;
1456         float vec[2];
1457         
1458         vec[0]= (G.scene->r.cfra);
1459         vec[0]*= G.scene->r.framelen;
1460         
1461         vec[1]= v2d->cur.ymin;
1462         glColor3ub(0x60, 0xc0, 0x40);   // no theme, should be global color once...
1463         glLineWidth(2.0);
1464         
1465         glBegin(GL_LINE_STRIP);
1466         glVertex2fv(vec);
1467         vec[1]= v2d->cur.ymax;
1468         glVertex2fv(vec);
1469         glEnd();
1470         
1471         if(sipo->blocktype==ID_OB) {
1472                 ob= (G.scene->basact) ? (G.scene->basact->object) : 0;
1473                 if(ob && ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
1474                         vec[0]-= ob->sf;
1475                         
1476                         BIF_ThemeColorShade(TH_HILITE, -30);
1477                         
1478                         glBegin(GL_LINE_STRIP);
1479                         glVertex2fv(vec);
1480                         vec[1]= G.v2d->cur.ymin;
1481                         glVertex2fv(vec);
1482                         glEnd();
1483                 }
1484         }
1485         
1486         glLineWidth(1.0);
1487 }
1488
1489 static void draw_ipokey(SpaceIpo *sipo)
1490 {
1491         IpoKey *ik;
1492         
1493         glBegin(GL_LINES);
1494         for (ik= sipo->ipokey.first; ik; ik= ik->next) {
1495                 if(ik->flag & 1) glColor3ub(0xFF, 0xFF, 0x99);
1496                 else glColor3ub(0xAA, 0xAA, 0x55);
1497                 
1498                 glVertex2f(ik->val, G.v2d->cur.ymin);
1499                 glVertex2f(ik->val, G.v2d->cur.ymax);
1500         }
1501         glEnd();
1502 }
1503
1504 static void draw_key(SpaceIpo *sipo, int visible)
1505 {
1506         View2D *v2d= &sipo->v2d;
1507         Key *key;
1508         KeyBlock *kb, *act=NULL;
1509         Object *ob= OBACT;
1510         unsigned int col;
1511         int index;
1512         
1513         key= ob_get_key((Object *)sipo->from);
1514         if(key==NULL)
1515                 return;
1516         
1517         if(key->type== KEY_RELATIVE) if(visible==0) return;
1518         
1519         for(index=1, kb= key->block.first; kb; kb= kb->next, index++) {
1520                 if(kb->type==KEY_LINEAR) setlinestyle(2);
1521                 else if(kb->type==KEY_BSPLINE) setlinestyle(4);
1522                 else setlinestyle(0);
1523                 
1524                 if(kb==key->refkey) col= 0x22FFFF;
1525                 else col= 0xFFFF00;
1526                 
1527                 if(ob->shapenr!=index) col-= 0x225500;
1528                 else act= kb;
1529                 
1530                 cpack(col);
1531                 
1532                 glBegin(GL_LINE_STRIP);
1533                 glVertex2f(v2d->cur.xmin, kb->pos);
1534                 glVertex2f(v2d->cur.xmax, kb->pos);
1535                 glEnd();
1536                 
1537         }
1538         
1539         if(act) {
1540                 if(act->type==KEY_LINEAR) setlinestyle(2);
1541                 else if(act->type==KEY_BSPLINE) setlinestyle(4);
1542                 else setlinestyle(0);
1543                 
1544                 if(act==key->refkey) cpack(0x22FFFF);
1545                 else cpack(0xFFFF00);
1546                 
1547                 glBegin(GL_LINE_STRIP);
1548                 glVertex2f(v2d->cur.xmin, act->pos);
1549                 glVertex2f(v2d->cur.xmax, act->pos);
1550                 glEnd();
1551         }
1552         
1553         setlinestyle(0);
1554 }
1555
1556 /* ************************** buttons *********************** */
1557
1558
1559 #define B_SETSPEED              3401
1560 #define B_MUL_IPO               3402
1561 #define B_TRANS_IPO             3403
1562 #define B_IPO_NONE              3404
1563 #define B_IPO_DRIVER    3405
1564 #define B_IPO_REDR              3406
1565 #define B_IPO_DEPCHANGE 3407
1566 #define B_IPO_DRIVERTYPE 3408
1567
1568 static float hspeed= 0;
1569
1570 static void boundbox_ipo_curves(SpaceIpo *si)
1571 {
1572         EditIpo *ei;
1573         Key *key;
1574         KeyBlock *kb;
1575         int a, first= 1;
1576
1577         ei= si->editipo;
1578         if(ei==0)
1579                 return;
1580
1581         for(a=0; a<si->totipo; a++, ei++) {
1582                 
1583                 if(ei->icu) {
1584                         if(ei->flag & IPO_VISIBLE) {
1585         
1586                                 boundbox_ipocurve(ei->icu);
1587                                 if(first) {
1588                                         si->v2d.tot= ei->icu->totrct;
1589                                         first= 0;
1590                                 }
1591                                 else BLI_union_rctf(&(si->v2d.tot), &(ei->icu->totrct));
1592                         }
1593                 }
1594         }
1595         /* keylines? */
1596         if(si->blocktype==ID_KE) {
1597                 key= ob_get_key((Object *)si->from);
1598                 if(key && key->block.first) {
1599                         kb= key->block.first;
1600                         if(kb->pos < si->v2d.tot.ymin) si->v2d.tot.ymin= kb->pos;
1601                         kb= key->block.last;
1602                         if(kb->pos > si->v2d.tot.ymax) si->v2d.tot.ymax= kb->pos;
1603                 }
1604         }
1605         si->tot= si->v2d.tot;
1606 }
1607
1608
1609 /* is used for both read and write... */
1610 static void ipo_editvertex_buts(uiBlock *block, SpaceIpo *si, float min, float max)
1611 {
1612         Object *ob= OBACT;
1613         EditIpo *ei;
1614         BezTriple *bezt;
1615         float median[3];
1616         int a, b, tot, iskey=0;
1617         
1618         median[0]= median[1]= median[2]= 0.0;
1619         tot= 0;
1620         
1621         ei= G.sipo->editipo;
1622         for(a=0; a<G.sipo->totipo; a++, ei++) {
1623                 
1624                 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
1625                         if( (ei->flag & IPO_EDIT) || G.sipo->showkey) {
1626
1627                                 if(ei->icu->bezt) {
1628                                         bezt= ei->icu->bezt;
1629                                         b= ei->icu->totvert;
1630                                         while(b--) {
1631                                                 // all three selected 
1632                                                 if(bezt->f2 & 1) {
1633                                                         VecAddf(median, median, bezt->vec[1]);
1634                                                         tot++;
1635                                                 }
1636                                                 else {
1637                                                         if(bezt->f1 & 1) {
1638                                                                 VecAddf(median, median, bezt->vec[0]);
1639                                                                 tot++;
1640                                                         }
1641                                                         if(bezt->f3 & 1) {
1642                                                                 VecAddf(median, median, bezt->vec[2]);
1643                                                                 tot++;
1644                                                         }
1645                                                 }
1646                                                 bezt++;
1647                                         }
1648                                         
1649                                 }
1650                         }
1651                 }
1652         }
1653         /* check for keys */
1654         if(tot==0) {
1655                 if(G.sipo->blocktype==ID_KE) {
1656                         Key *key= ob_get_key((Object *)G.sipo->from);
1657                         KeyBlock *kb;
1658                         
1659                         if(key==NULL || ob->shapenr==0) return;
1660                         iskey= 1;
1661                         
1662                         kb= BLI_findlink(&key->block, ob->shapenr-1);
1663                         median[1]+= kb->pos;
1664                         tot++;
1665                 }
1666         }
1667         if(tot==0) return;
1668
1669         median[0] /= (float)tot;
1670         median[1] /= (float)tot;
1671         median[2] /= (float)tot;
1672         
1673         if(block) {     // buttons
1674         
1675                 VECCOPY(si->median, median);
1676                 
1677                 uiBlockBeginAlign(block);
1678                 if(tot==1) {
1679                         if(iskey) 
1680                                 uiDefButF(block, NUM, B_TRANS_IPO, "Key Y:",    10, 80, 300, 19, &(si->median[1]), min, max, 10, 0, "");
1681                         else {
1682                                 uiDefButF(block, NUM, B_TRANS_IPO, "Vertex X:", 10, 100, 150, 19, &(si->median[0]), min, max, 100, 0, "");
1683                                 uiDefButF(block, NUM, B_TRANS_IPO, "Vertex Y:", 160, 100, 150, 19, &(si->median[1]), min, max, 100, 0, "");
1684                         }
1685                 }
1686                 else {
1687                         if(iskey) 
1688                                 uiDefButF(block, NUM, B_TRANS_IPO, "Median Key Y:",     10, 80, 300, 19, &(si->median[1]), min, max, 10, 0, "");
1689                         else {
1690                                 uiDefButF(block, NUM, B_TRANS_IPO, "Median X:", 10, 100, 150, 19, &(si->median[0]), min, max, 100, 0, "");
1691                                 uiDefButF(block, NUM, B_TRANS_IPO, "Median Y:", 160, 100, 150, 19, &(si->median[1]), min, max, 100, 0, "");
1692                         }
1693                 }
1694         }
1695         else if(iskey) {        // apply
1696                 VecSubf(median, si->median, median);
1697
1698                 if(G.sipo->blocktype==ID_KE) {
1699                         Key *key= ob_get_key((Object *)G.sipo->from);
1700                         KeyBlock *kb;
1701                         
1702                         if(key==NULL || ob->shapenr==0) return;
1703                         
1704                         kb= BLI_findlink(&key->block, ob->shapenr-1);
1705                         kb->pos+= median[1];
1706                         tot++;
1707
1708                         sort_keys(key);
1709                 }
1710         }
1711         else {
1712                 
1713                 VecSubf(median, si->median, median);
1714
1715                 ei= G.sipo->editipo;
1716                 for(a=0; a<G.sipo->totipo; a++, ei++) {
1717                         
1718                         if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
1719                                 if( (ei->flag & IPO_EDIT) || G.sipo->showkey) {
1720
1721                                         if(ei->icu->bezt) {
1722                                                 bezt= ei->icu->bezt;
1723                                                 b= ei->icu->totvert;
1724                                                 while(b--) {
1725                                                         // all three selected
1726                                                         if(bezt->f2 & 1) {
1727                                                                 VecAddf(bezt->vec[0], bezt->vec[0], median);
1728                                                                 VecAddf(bezt->vec[1], bezt->vec[1], median);
1729                                                                 VecAddf(bezt->vec[2], bezt->vec[2], median);
1730                                                         }
1731                                                         else {
1732                                                                 if(bezt->f1 & 1) {
1733                                                                         VecAddf(bezt->vec[0], bezt->vec[0], median);
1734                                                                 }
1735                                                                 if(bezt->f3 & 1) {
1736                                                                         VecAddf(bezt->vec[2], bezt->vec[2], median);
1737                                                                 }
1738                                                         }
1739                                                         bezt++;
1740                                                 }
1741                                                 
1742                                         }
1743                                 }
1744                         }
1745                 }
1746         }
1747 }
1748
1749 void do_ipobuts(unsigned short event)
1750 {
1751         Object *ob= OBACT;
1752         EditIpo *ei;
1753         
1754         if(G.sipo->from==NULL) return;
1755         
1756         switch(event) {
1757         case B_IPO_REDR:
1758                 ei= get_active_editipo();
1759                 if(ei) {
1760                         if(ei->icu->driver) {
1761                                 if (ei->icu->driver->type == IPO_DRIVER_TYPE_PYTHON) {
1762                                         /* eval user's expression once for validity */
1763                                         BPY_pydriver_eval(ei->icu->driver);
1764                                         DAG_scene_sort(G.scene);
1765                                 }
1766                                 else if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC) 
1767                                         DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
1768                                 else
1769                                         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
1770                         }
1771                 }
1772                 allqueue(REDRAWIPO, 0);
1773                 allqueue(REDRAWVIEW3D, 0);
1774                 break;
1775         case B_SETSPEED:
1776                 set_speed_editipo(hspeed);
1777                 break;
1778         case B_MUL_IPO:
1779                 scale_editipo();
1780                 allqueue(REDRAWIPO, 0);
1781                 break;
1782         case B_TRANS_IPO:
1783                 ipo_editvertex_buts(NULL, G.sipo, 0.0, 0.0);
1784                 editipo_changed(G.sipo, 1);
1785                 allqueue(REDRAWIPO, 0);
1786                 break;
1787         case B_SETKEY:
1788                 ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
1789                 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
1790                 allqueue(REDRAWVIEW3D, 0);
1791                 allqueue(REDRAWIPO, 0);
1792                 allqueue(REDRAWBUTSEDIT, 0);
1793                 break;
1794         case B_IPO_DRIVER:
1795                 ei= get_active_editipo();
1796                 if(ei) {
1797                         if(ei->icu==NULL) {
1798                                 ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei->adrcode);
1799                                 ei->flag |= IPO_SELECT;
1800                                 ei->icu->flag= ei->flag;
1801                         }
1802                         if(ei->icu->driver) {
1803                                 MEM_freeN(ei->icu->driver);
1804                                 ei->icu->driver= NULL;
1805                                 if(ei->icu->bezt==NULL) {
1806                                         BLI_remlink( &(G.sipo->ipo->curve), ei->icu);
1807                                         free_ipo_curve(ei->icu);
1808                                         ei->icu= NULL;
1809                                 }
1810                         }
1811                         else {
1812                                 ei->icu->driver= MEM_callocN(sizeof(IpoDriver), "ipo driver");
1813                                 ei->icu->driver->blocktype= ID_OB;
1814                                 ei->icu->driver->adrcode= OB_LOC_X;
1815                         }
1816
1817                         allqueue(REDRAWVIEW3D, 0);
1818                         allqueue(REDRAWIPO, 0);
1819                         allqueue(REDRAWBUTSEDIT, 0);
1820                         DAG_scene_sort(G.scene);
1821                         
1822                         BIF_undo_push("Add/Remove Ipo driver");
1823                 }
1824                 break;
1825         case B_IPO_DRIVERTYPE:
1826                 ei= get_active_editipo();
1827                 if(ei) {
1828                         if(ei->icu->driver) {
1829                                 IpoDriver *driver= ei->icu->driver;
1830
1831                                 if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
1832                                         /* pydriver expression shouldn't reference own ob,
1833                                          * so we need to store ob ptr to check against it */
1834                                         driver->ob= ob;
1835                                 }
1836                                 else {
1837                                         driver->ob= NULL;
1838                                         driver->blocktype= ID_OB;
1839                                         driver->adrcode= OB_LOC_X;
1840                                         driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
1841                                 }
1842                         }
1843                         allqueue(REDRAWVIEW3D, 0);
1844                         allqueue(REDRAWIPO, 0);
1845                         allqueue(REDRAWBUTSEDIT, 0);
1846                         DAG_scene_sort(G.scene);
1847         
1848                         BIF_undo_push("Change Ipo driver type");
1849                 }
1850                 break;
1851         case B_IPO_DEPCHANGE:
1852                 ei= get_active_editipo();
1853                 if(ei) {
1854                         if(ei->icu->driver) {
1855                                 IpoDriver *driver= ei->icu->driver;
1856                                 
1857                                 if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
1858                                 }
1859                                 else {
1860                                         if(driver->ob) {
1861                                                 if(ob==driver->ob) {
1862                                                         error("Cannot assign a Driver to own Object");
1863                                                         driver->ob= NULL;
1864                                                 }
1865                                                 else {
1866                                                         /* check if type is still OK */
1867                                                         if(driver->ob->type==OB_ARMATURE && driver->blocktype==ID_AR);
1868                                                         else driver->blocktype= ID_OB;
1869                                                 }
1870                                         }
1871                                 }
1872                                 DAG_scene_sort(G.scene);
1873                                 
1874                                 if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC) 
1875                                         DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
1876                                 else
1877                                         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
1878                         }
1879                 }
1880                 allqueue(REDRAWVIEW3D, 0);
1881                 allqueue(REDRAWIPO, 0);
1882                 allqueue(REDRAWBUTSEDIT, 0);
1883                 break;
1884         }
1885 }
1886
1887 static char *ipodriver_modeselect_pup(Object *ob)
1888 {
1889         static char string[265];
1890         char tmpstr[64];
1891         char formatstring[64];
1892         
1893         strcpy(string, "Driver type: %t");
1894         
1895         strcpy(formatstring, "|%s %%x%d %%i%d");
1896         
1897         if(ob) {
1898                 sprintf(tmpstr,formatstring,"Object",ID_OB, ICON_OBJECT);
1899                 strcat(string,tmpstr);
1900         }
1901         if(ob && ob->type==OB_ARMATURE) {
1902                 sprintf(tmpstr,formatstring,"Pose",ID_AR, ICON_POSE_DEHLT);
1903                 strcat(string,tmpstr);
1904         }
1905         
1906         return (string);
1907 }
1908
1909 static char *ipodriver_channelselect_pup(void)
1910 {
1911         static char string[1024];
1912         char *tmp;
1913         
1914         strcpy(string, "Driver channel: %t");
1915         tmp= string+strlen(string);
1916         
1917         tmp+= sprintf(tmp, "|Loc X %%x%d", OB_LOC_X);
1918         tmp+= sprintf(tmp, "|Loc Y %%x%d", OB_LOC_Y);
1919         tmp+= sprintf(tmp, "|Loc Z %%x%d", OB_LOC_Z);
1920         tmp+= sprintf(tmp, "|Rot X %%x%d", OB_ROT_X);
1921         tmp+= sprintf(tmp, "|Rot Y %%x%d", OB_ROT_Y);
1922         tmp+= sprintf(tmp, "|Rot Z %%x%d", OB_ROT_Z);
1923         tmp+= sprintf(tmp, "|Size X %%x%d", OB_SIZE_X);
1924         tmp+= sprintf(tmp, "|Size Y %%x%d", OB_SIZE_Y);
1925         tmp+= sprintf(tmp, "|Size Z %%x%d", OB_SIZE_Z);
1926         
1927         return (string);
1928 }
1929
1930 static void ipo_panel_properties(short cntrl)   // IPO_HANDLER_PROPERTIES
1931 {
1932         extern int totipo_curve;        // editipo.c
1933         uiBlock *block;
1934         EditIpo *ei;
1935         char name[48];
1936         
1937         block= uiNewBlock(&curarea->uiblocks, "ipo_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
1938         uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
1939         uiSetPanelHandler(IPO_HANDLER_PROPERTIES);  // for close and esc
1940         if(uiNewPanel(curarea, block, "Transform Properties", "Ipo", 10, 230, 318, 204)==0) return;
1941
1942         /* this is new panel height, newpanel doesnt force new size on existing panels */
1943         uiNewPanelHeight(block, 204);
1944         
1945         /* driver buttons first */
1946         ei= get_active_editipo();
1947         if(ei) {
1948                 
1949                 sprintf(name, "Driven Channel: %s", ei->name);
1950                 uiDefBut(block, LABEL, 0, name,         10, 265, 200, 19, NULL, 1.0, 0.0, 0, 0, "");
1951                 
1952                 if(ei->icu && ei->icu->driver) {
1953                         IpoDriver *driver= ei->icu->driver;
1954
1955                         uiDefBut(block, BUT, B_IPO_DRIVER, "Remove",                            210,265,100,20, NULL, 0.0f, 0.0f, 0, 0, "Remove Driver for this Ipo Channel");
1956                         
1957                         uiBlockBeginAlign(block);
1958                         uiDefIconButS(block, TOG, B_IPO_DRIVERTYPE, ICON_PYTHON, 10,240,25,20, &driver->type, (float)IPO_DRIVER_TYPE_NORMAL, (float)IPO_DRIVER_TYPE_PYTHON, 0, 0, "Use a one-line Python Expression as Driver");
1959
1960                         if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
1961                                 uiDefBut(block, TEX, B_IPO_REDR, "",                            35,240,275,20, driver->name, 0, 127, 0, 0, "Python Expression");
1962                                 if(driver->flag & IPO_DRIVER_FLAG_INVALID) {
1963                                         uiDefBut(block, LABEL, 0, "Error: invalid Python expression",
1964                                                         5,215,230,19, NULL, 0, 0, 0, 0, "");
1965                                 }
1966                                 uiBlockEndAlign(block);
1967                         }
1968                         else {
1969                                 uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_IPO_DEPCHANGE, "OB:",   35, 240, 125, 20, &(driver->ob), "Driver Object");
1970                                 if(driver->ob) {
1971                                         int icon=ICON_OBJECT;
1972                                         
1973                                         if(driver->ob->type==OB_ARMATURE && driver->blocktype==ID_AR) {
1974                                                 icon = ICON_POSE_DEHLT;
1975                                                 uiDefBut(block, TEX, B_IPO_REDR, "BO:",                         10,220,150,20, driver->name, 0, 31, 0, 0, "Bone name");
1976                                         }
1977                                         else driver->blocktype= ID_OB;  /* safety when switching object button */
1978                                         
1979                                         uiBlockBeginAlign(block);
1980                                         uiDefIconTextButS(block, MENU, B_IPO_DEPCHANGE, icon, 
1981                                                                           ipodriver_modeselect_pup(driver->ob), 165,240,145,20, &(driver->blocktype), 0, 0, 0, 0, "Driver type");
1982
1983                                         uiDefButS(block, MENU, B_IPO_REDR, 
1984                                                                 ipodriver_channelselect_pup(),                  165,220,145,20, &(driver->adrcode), 0, 0, 0, 0, "Driver channel");
1985                                 }
1986                                 uiBlockEndAlign(block);
1987                         }
1988                 }
1989                 else {
1990                         uiDefBut(block, BUT, B_IPO_DRIVER, "Add Driver",        210,265,100,19, NULL, 0.0f, 0.0f, 0, 0, "Create a Driver for this Ipo Channel");
1991                 }
1992         }
1993         else 
1994                 uiDefBut(block, LABEL, 0, " ",          10, 265, 150, 19, NULL, 1.0, 0.0, 0, 0, "");
1995
1996         boundbox_ipo_curves(G.sipo);    // should not be needed... transform/draw calls should update
1997         
1998         /* note ranges for buttons below are idiot... we need 2 ranges, one for sliding scale, one for real clip */
1999         if(G.sipo->ipo && G.sipo->ipo->curve.first && totipo_curve) {
2000                 extern int totipo_vertsel;      // editipo.c
2001                 uiDefBut(block, LABEL, 0, "Visible curves",             10, 200, 150, 19, NULL, 1.0, 0.0, 0, 0, "");
2002                 
2003                 uiBlockBeginAlign(block);
2004                 uiDefButF(block, NUM, B_MUL_IPO, "Xmin:",               10, 180, 150, 19, &G.sipo->tot.xmin, G.sipo->tot.xmin-1000.0, MAXFRAMEF, 100, 0, "");
2005                 uiDefButF(block, NUM, B_MUL_IPO, "Xmax:",               160, 180, 150, 19, &G.sipo->tot.xmax, G.sipo->tot.ymin-1000.0, MAXFRAMEF, 100, 0, "");
2006                 
2007                 uiDefButF(block, NUM, B_MUL_IPO, "Ymin:",               10, 160, 150, 19, &G.sipo->tot.ymin, G.sipo->tot.ymin-1000.0, 5000.0, 100, 0, "");
2008                 uiDefButF(block, NUM, B_MUL_IPO, "Ymax:",               160, 160, 150, 19, &G.sipo->tot.ymax, G.sipo->tot.ymin-1000.0, 5000.0, 100, 0, "");
2009
2010                 /* SPEED BUTTON */
2011                 if(totipo_vertsel) {
2012                         uiBlockBeginAlign(block);
2013                         uiDefButF(block, NUM, B_IPO_NONE, "Speed:",             10,130,150,19, &hspeed, 0.0, 180.0, 1, 0, "");
2014                         uiDefBut(block, BUT, B_SETSPEED,"SET",                  160,130,50,19, 0, 0, 0, 0, 0, "");
2015                 }
2016         }
2017
2018         /* this one also does keypositions */
2019         if(G.sipo->ipo) ipo_editvertex_buts(block, G.sipo, -10000, MAXFRAMEF);
2020 }
2021
2022 static void ipo_blockhandlers(ScrArea *sa)
2023 {
2024         SpaceIpo *sipo= sa->spacedata.first;
2025         short a;
2026
2027         /* warning; blocks need to be freed each time, handlers dont remove (for ipo moved to drawipospace) */
2028
2029         for(a=0; a<SPACE_MAXHANDLER; a+=2) {
2030                 switch(sipo->blockhandler[a]) {
2031
2032                 case IPO_HANDLER_PROPERTIES:
2033                         ipo_panel_properties(sipo->blockhandler[a+1]);
2034                         break;
2035                 
2036                 }
2037                 /* clear action value for event */
2038                 sipo->blockhandler[a+1]= 0;
2039         }
2040         uiDrawBlocksPanels(sa, 0);
2041
2042 }
2043
2044
2045 void drawipospace(ScrArea *sa, void *spacedata)
2046 {
2047         SpaceIpo *sipo= sa->spacedata.first;
2048         View2D *v2d= &sipo->v2d;
2049         EditIpo *ei;
2050         float col[3];
2051         int ofsx, ofsy, a, disptype;
2052
2053         bwin_clear_viewmat(sa->win);    /* clear buttons view */
2054         glLoadIdentity();
2055         
2056         uiFreeBlocksWin(&sa->uiblocks, sa->win);        /* for panel handler to work */
2057         
2058         test_editipo(0);        /* test if current editipo is correct, make_editipo sets v2d->cur, call here because of calc_ipobuttonswidth() */
2059         
2060         v2d->hor.xmax+=calc_ipobuttonswidth(sa);
2061         calc_scrollrcts(sa, G.v2d, sa->winx, sa->winy);
2062
2063         BIF_GetThemeColor3fv(TH_BACK, col);
2064         glClearColor(col[0], col[1], col[2], 0.0); 
2065
2066         if (sipo->pin)
2067                 glClearColor(col[0]+0.05,col[1],col[2], 0.0);   // litepink
2068         else
2069                 glClearColor(col[0],col[1],col[2], 0.0);
2070
2071         glClear(GL_COLOR_BUFFER_BIT);
2072         
2073         if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
2074                 if(v2d->scroll) {       
2075                         ofsx= sa->winrct.xmin;  // ivm mywin 
2076                         ofsy= sa->winrct.ymin;
2077                         glViewport(ofsx+v2d->mask.xmin,  ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1); 
2078                         glScissor(ofsx+v2d->mask.xmin,  ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1);
2079                 } 
2080         }
2081
2082         myortho2(v2d->cur.xmin, v2d->cur.xmax, v2d->cur.ymin, v2d->cur.ymax);
2083  
2084         if(sipo->editipo) {
2085                 
2086                 /* correct scale for degrees? */
2087                 disptype= -1;
2088                 ei= sipo->editipo;
2089                 for(a=0; a<sipo->totipo; a++, ei++) {
2090                         if(ei->flag & IPO_VISIBLE) {
2091                                 if(disptype== -1) disptype= ei->disptype;
2092                                 else if(disptype!=ei->disptype) disptype= 0;
2093                         }
2094                 }
2095                 
2096                 calc_ipogrid(); 
2097                 draw_ipogrid();
2098                 
2099                 draw_cfra(sipo);
2100                 
2101                 /* ipokeys */
2102                 if(sipo->showkey) {
2103                         if(sipo->ipokey.first==0) make_ipokey();
2104                         draw_ipokey(sipo);
2105                 }
2106                 
2107                 if(sipo->blocktype==ID_KE) {
2108                         ei= sipo->editipo;
2109                         draw_key(sipo, ei->flag & IPO_VISIBLE);
2110                 }
2111
2112                 /* draw deselect */
2113                 draw_ipocurves(0);
2114                 draw_ipohandles(0);
2115                 draw_ipovertices(0);
2116                 
2117                 /* draw select */
2118                 draw_ipocurves(1);
2119                 draw_ipohandles(1);
2120                 draw_ipovertices(1);
2121                 
2122                 /* restore viewport */
2123                 mywinset(sa->win);
2124                 
2125                 if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
2126                         
2127                         /* ortho at pixel level sa */
2128                         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
2129                         
2130                         if(v2d->scroll) {
2131                                 drawscroll(disptype);
2132                                 draw_solution(sipo);
2133                         }
2134                         
2135                         draw_ipobuts(sipo);
2136                 }
2137         }
2138         else {
2139                 calc_ipogrid();
2140                 draw_ipogrid();
2141         }
2142         
2143         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
2144         draw_area_emboss(sa);
2145
2146         /* it is important to end a view in a transform compatible with buttons */
2147         bwin_scalematrix(sa->win, sipo->blockscale, sipo->blockscale, sipo->blockscale);
2148         /* only draw panels when relevant */
2149         if(sipo->editipo) ipo_blockhandlers(sa);
2150
2151         sa->win_swap= WIN_BACK_OK;
2152 }
2153
2154 void scroll_ipobuts()
2155 {
2156         int tot;
2157         short yo, mval[2];
2158         
2159         tot= 30+IPOBUTY*G.sipo->totipo;
2160         if(tot<curarea->winy) return;
2161         
2162         getmouseco_areawin(mval);
2163         yo= mval[1];
2164         
2165         while(get_mbut()&M_MOUSE) {
2166                 getmouseco_areawin(mval);
2167                 if(mval[1]!=yo) {
2168                         G.sipo->butofs+= (mval[1]-yo);
2169                         if(G.sipo->butofs<0) G.sipo->butofs= 0;
2170                         else if(G.sipo->butofs+curarea->winy>tot) G.sipo->butofs= tot-curarea->winy;
2171                         
2172                         scrarea_do_windraw(curarea);
2173                         screen_swapbuffers();
2174                         
2175                         yo= mval[1];
2176                 }
2177                 else BIF_wait_for_statechange();
2178         }
2179 }
2180
2181 /* total mess function, especially with mousewheel, needs cleanup badly (ton) */
2182 int view2dzoom(unsigned short event)
2183 {
2184         ScrArea *sa;
2185         float fac, dx, dy, wtemp;
2186         short mval[2], mvalo[2];
2187         short is_wheel= (event==WHEELUPMOUSE) || (event==WHEELDOWNMOUSE);
2188         
2189         getmouseco_areawin(mvalo);
2190         mval[0]= mvalo[0];
2191         mval[1]= mvalo[1];
2192         
2193         while( (get_mbut()&(L_MOUSE|M_MOUSE)) || is_wheel ) {
2194         
2195                 /* regular mousewheel:   zoom regular
2196                 * alt-shift mousewheel: zoom y only
2197                 * alt-ctrl mousewheel:  zoom x only
2198                 */
2199                 if (event==WHEELUPMOUSE) {
2200                         if(U.uiflag & USER_WHEELZOOMDIR)
2201                                 wtemp = -0.0375;
2202                         else
2203                                 wtemp = 0.03;
2204                         if(curarea->spacetype!=SPACE_BUTS) wtemp*= 3;
2205                         
2206                         dx= (float)(wtemp*(G.v2d->cur.xmax-G.v2d->cur.xmin));
2207                         dy= (float)(wtemp*(G.v2d->cur.ymax-G.v2d->cur.ymin));
2208                         
2209                         switch (G.qual & (LR_CTRLKEY|LR_SHIFTKEY|LR_ALTKEY)) {
2210                         case 0:
2211                                 break;
2212                         case (LR_SHIFTKEY|LR_ALTKEY):
2213                                 dx = 0;
2214                                 break;
2215                         case (LR_CTRLKEY|LR_ALTKEY):
2216                                 dy = 0;
2217                                 break;
2218                         default:
2219                                 if(curarea->spacetype==SPACE_BUTS);     // exception
2220                                 else return 0;
2221                                 break;
2222                         }
2223                 }
2224                 else if (event==WHEELDOWNMOUSE) {
2225                         if(U.uiflag & USER_WHEELZOOMDIR)
2226                                 wtemp = 0.03;
2227                         else
2228                                 wtemp = -0.0375;
2229                         if(curarea->spacetype!=SPACE_BUTS) wtemp*= 3;
2230                         
2231                         dx= (float)(wtemp*(G.v2d->cur.xmax-G.v2d->cur.xmin));
2232                         dy= (float)(wtemp*(G.v2d->cur.ymax-G.v2d->cur.ymin));
2233                         
2234                         switch (G.qual & (LR_CTRLKEY|LR_SHIFTKEY|LR_ALTKEY)) {
2235                                 case 0:
2236                                 break;
2237                         case (LR_SHIFTKEY|LR_ALTKEY):
2238                                 dx = 0;
2239                                 break;
2240                         case (LR_CTRLKEY|LR_ALTKEY):
2241                                 dy = 0;
2242                                 break;
2243                         default:
2244                                 if(curarea->spacetype==SPACE_BUTS);
2245                                 else return 0;
2246                                 break;
2247                         }
2248                 }
2249                 else {
2250                         getmouseco_areawin(mval);
2251                         if(U.viewzoom==USER_ZOOM_SCALE) {
2252                                 float dist;
2253                                 
2254                                 dist = (G.v2d->mask.xmax - G.v2d->mask.xmin)/2.0;
2255                                 dx= 1.0-(fabs(mvalo[0]-dist)+2.0)/(fabs(mval[0]-dist)+2.0);
2256                                 dx*= 0.5*(G.v2d->cur.xmax-G.v2d->cur.xmin);
2257
2258                                 dist = (G.v2d->mask.ymax - G.v2d->mask.ymin)/2.0;
2259                                 dy= 1.0-(fabs(mvalo[1]-dist)+2.0)/(fabs(mval[1]-dist)+2.0);
2260                                 dy*= 0.5*(G.v2d->cur.ymax-G.v2d->cur.ymin);
2261         
2262                         }
2263                         else {
2264                                 fac= 0.01*(mval[0]-mvalo[0]);
2265                                 dx= fac*(G.v2d->cur.xmax-G.v2d->cur.xmin);
2266                                 fac= 0.01*(mval[1]-mvalo[1]);
2267                                 dy= fac*(G.v2d->cur.ymax-G.v2d->cur.ymin);
2268                                 
2269                                 if(U.viewzoom==USER_ZOOM_CONT) {
2270                                         dx/= 20.0;
2271                                         dy/= 20.0;
2272                                 }
2273                         }
2274                 }
2275                 if (ELEM(event, WHEELUPMOUSE, WHEELDOWNMOUSE) || mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
2276                         
2277                         if(U.viewzoom!=USER_ZOOM_CONT) {
2278                                 mvalo[0]= mval[0];
2279                                 mvalo[1]= mval[1];
2280                         }
2281                         
2282                         if( ELEM(curarea->spacetype, SPACE_NLA, SPACE_ACTION) ) {
2283                                 if(mvalo[0] < G.v2d->mask.xmin) {
2284                                         G.v2d->cur.ymin+= dy;
2285                                         G.v2d->cur.ymax-= dy;
2286                                 }
2287                                 else {
2288                                         G.v2d->cur.xmin+= dx;
2289                                         G.v2d->cur.xmax-= dx;
2290                                 }
2291                         }
2292                         else if (ELEM(curarea->spacetype, SPACE_SOUND, SPACE_TIME)) {
2293                                 G.v2d->cur.xmin+= dx;
2294                                 G.v2d->cur.xmax-= dx;
2295                         }
2296                         else if (curarea->spacetype == SPACE_SEQ) {
2297                                 /* less sensitivity on y scale */
2298                                 G.v2d->cur.xmin+= dx;
2299                                 G.v2d->cur.xmax-= dx;
2300                                 if (!(ELEM(event, WHEELUPMOUSE, WHEELDOWNMOUSE))) {
2301                                         G.v2d->cur.ymin+= dy/2;
2302                                         G.v2d->cur.ymax-= dy/2;
2303                                 }
2304                         }
2305                         else {
2306                                 G.v2d->cur.xmin+= dx;
2307                                 G.v2d->cur.xmax-= dx;
2308                                 G.v2d->cur.ymin+= dy;
2309                                 G.v2d->cur.ymax-= dy;
2310                         }
2311                 
2312                         test_view2d(G.v2d, curarea->winx, curarea->winy);       /* cur min max rects */
2313                         
2314                         sa= curarea;    /* now when are you going to kill this one! */
2315                         view2d_do_locks(curarea, V2D_LOCK_COPY|V2D_LOCK_REDRAW);
2316                         mywinset(sa->win);
2317                         
2318                         scrarea_do_windraw(curarea);
2319                         screen_swapbuffers();
2320                 }
2321                 else BIF_wait_for_statechange();
2322                 /* return if we were using the mousewheel
2323                 */
2324                 if ( is_wheel ) return 1;
2325         }
2326         return 1;
2327 }
2328
2329 void center_currframe(void)
2330 {
2331         /* place the current frame in the
2332          * center of the 2D window.
2333          */
2334         float width;
2335   
2336         width = G.v2d->cur.xmax - G.v2d->cur.xmin;
2337         G.v2d->cur.xmin = CFRA - 0.5*(width);
2338         G.v2d->cur.xmax = CFRA + 0.5*(width);
2339
2340         test_view2d(G.v2d, curarea->winx, curarea->winy);
2341         view2d_do_locks(curarea, V2D_LOCK_COPY);
2342
2343         scrarea_queue_winredraw(curarea);
2344 }
2345
2346 /* total mess function, especially with mousewheel, needs cleanup badly (ton) */
2347 int view2dmove(unsigned short event)
2348 {
2349         /* return 1 when something was done */
2350         float facx=0.0, facy=0.0, dx, dy, left=1.0, right=1.0;
2351         short mval[2], mvalo[2], leftret=1, mousebut;
2352         short is_wheel= (event==WHEELUPMOUSE) || (event==WHEELDOWNMOUSE);
2353         
2354         /* when wheel is used, we only draw it once */
2355         
2356         /* try to do some zooming if the
2357          * middlemouse and ctrl are pressed
2358          * or if the mousewheel is being used.
2359          * Return if zooming was done.
2360          */
2361         
2362         /* check for left mouse / right mouse button select */
2363         if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
2364                 else mousebut = L_MOUSE;
2365         
2366         if ( (G.qual & LR_CTRLKEY) || is_wheel ) {
2367                 /* patch for oops & buttonswin, standard scroll no zoom */
2368                 if(curarea->spacetype==SPACE_OOPS) {
2369                         SpaceOops *soops= curarea->spacedata.first;
2370                         if(soops->type==SO_OUTLINER);
2371                         else if (view2dzoom(event)) {
2372                                 return 0;
2373                         }
2374                 }
2375                 else if(curarea->spacetype==SPACE_BUTS && (G.qual & LR_CTRLKEY)==0);
2376                 else if (view2dzoom(event)) {
2377                         return 0;
2378                 }
2379         }
2380         
2381         /* test where mouse is */
2382         getmouseco_areawin(mvalo);
2383         /* initialize this too */
2384         mval[0]= mvalo[0];
2385         mval[1]= mvalo[1];
2386         
2387         if ELEM7(curarea->spacetype, SPACE_IPO, SPACE_SEQ, SPACE_OOPS, SPACE_SOUND, SPACE_ACTION, SPACE_NLA, SPACE_TIME) {
2388
2389                 if( BLI_in_rcti(&G.v2d->mask, (int)mvalo[0], (int)mvalo[1]) ) {
2390                         facx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/(float)(G.v2d->mask.xmax-G.v2d->mask.xmin);
2391                         facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
2392                 }
2393                 /* stoopid exception to allow scroll in lefthand side */
2394                 else if(curarea->spacetype==SPACE_ACTION && BLI_in_rcti(&G.v2d->mask, ACTWIDTH+(int)mvalo[0], (int)mvalo[1]) ) {
2395                         facx= 0.0f;
2396                         facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
2397                 }
2398                 else if(curarea->spacetype==SPACE_NLA && BLI_in_rcti(&G.v2d->mask, NLAWIDTH+(int)mvalo[0], (int)mvalo[1]) ) {
2399                         facx= 0.0f;
2400                         facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
2401                 }
2402                 else if(IN_2D_VERT_SCROLL((int)mvalo)) {
2403                         facy= -(G.v2d->tot.ymax-G.v2d->tot.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
2404                         if(get_mbut() & mousebut) {
2405                                 /* which part of scrollbar should move? */
2406                                 if(mvalo[1]< (vertymin+vertymax)/2 ) right= 0.0;
2407                                 else left= 0.0;
2408                                 leftret= 0;
2409                         }
2410                         if(is_wheel)
2411                                 facy= -facy;
2412                 }
2413                 else if(IN_2D_HORIZ_SCROLL((int)mvalo)) {
2414                         facx= -(G.v2d->tot.xmax-G.v2d->tot.xmin)/(float)(G.v2d->mask.xmax-G.v2d->mask.xmin);
2415                         if(get_mbut() & mousebut) {
2416                                 /* which part of scrollbar should move? */
2417                                 if(mvalo[0]< (horxmin+horxmax)/2 ) right= 0.0;
2418                                 else left= 0.0;
2419                                 leftret= 0;
2420                         }
2421                 } 
2422         }
2423         else {
2424                 facx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/(float)(curarea->winx);
2425                 facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(curarea->winy);         
2426         }
2427                 
2428         /* no x move in outliner */
2429         if(curarea->spacetype==SPACE_OOPS && G.v2d->scroll) facx= 0.0;
2430         
2431         /* no y move in audio & time */
2432         if ELEM(curarea->spacetype, SPACE_SOUND, SPACE_TIME) facy= 0.0;
2433         
2434         if(get_mbut() & mousebut && leftret) return 0;
2435         if(facx==0.0 && facy==0.0) return 1;
2436         
2437         while( (get_mbut()&(L_MOUSE|M_MOUSE)) || is_wheel) {
2438
2439       /* If the mousewheel is used with shift key
2440        * the scroll up and down. If the mousewheel
2441        * is used with the ctrl key then scroll left
2442        * and right.
2443        */
2444                 if (is_wheel) {
2445                         if(event==WHEELDOWNMOUSE) {     
2446                                 facx= -facx; facy= -facy;
2447                         }
2448                         switch (G.qual & (LR_CTRLKEY|LR_SHIFTKEY|LR_ALTKEY)) {
2449                         case (LR_SHIFTKEY):
2450                                 dx = 0.0;
2451                                 dy= facy*20.0;
2452                                 break;
2453                         case (LR_CTRLKEY):
2454                                 dx= facx*20.0;
2455                                 dy = 0.0;
2456                                 break;
2457                         default:
2458                                 if(curarea->spacetype==SPACE_OOPS) {
2459                                         dx= 0.0;
2460                                         dy= facy*20;
2461                                 }
2462                                 else if(curarea->spacetype==SPACE_BUTS) {
2463                                         if(G.buts->align==BUT_HORIZONTAL) {
2464                                                 dx= facx*30; dy= 0.0;
2465                                         } else {
2466                                                 dx= 0.0; dy= facy*30;
2467                                         }
2468                                 }
2469                                 else return 0;
2470                                 break;
2471                         }
2472                 }
2473                 else {
2474                         getmouseco_areawin(mval);
2475                         dx= facx*(mvalo[0]-mval[0]);
2476                         dy= facy*(mvalo[1]-mval[1]);
2477                 }
2478
2479                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || is_wheel) {
2480                         ScrArea *sa;
2481                         
2482                         G.v2d->cur.xmin+= left*dx;
2483                         G.v2d->cur.xmax+= right*dx;
2484                         G.v2d->cur.ymin+= left*dy;
2485                         G.v2d->cur.ymax+= right*dy;
2486                         
2487                         test_view2d(G.v2d, curarea->winx, curarea->winy);
2488                         
2489                         sa= curarea;    /* bad global */
2490                         view2d_do_locks(curarea, V2D_LOCK_COPY|V2D_LOCK_REDRAW);
2491                         areawinset(sa->win);
2492                         
2493                         scrarea_do_windraw(curarea);
2494                         screen_swapbuffers();
2495                                 
2496                         mvalo[0]= mval[0];
2497                         mvalo[1]= mval[1];
2498                 }
2499                 else BIF_wait_for_statechange();
2500                         /* return if we were using the mousewheel
2501                         */
2502                 if ( is_wheel ) return 1;
2503         }
2504
2505     return 1;
2506 }
2507
2508 void view2dborder(void)
2509 {
2510         
2511 }
2512
2513 EditIpo *select_proj_ipo(rctf *rectf, int event)
2514 {
2515         EditIpo *ei;
2516         float xmin, ymin, xmax, ymax;
2517         /* this was IGLuint, but it's a useless typedef... */
2518         GLuint buffer[MAXPICKBUF];
2519         int a, b;
2520         int hits;
2521         unsigned int code;
2522         short mval[2];
2523         
2524         G.f |= G_PICKSEL;
2525         
2526         if(rectf==0) {
2527                 getmouseco_areawin(mval);
2528                 
2529                 mval[0]-= 6; mval[1]-= 6;
2530                 areamouseco_to_ipoco(G.v2d, mval, &xmin, &ymin);
2531                 mval[0]+= 12; mval[1]+= 12;
2532                 areamouseco_to_ipoco(G.v2d, mval, &xmax, &ymax);
2533                 
2534                 myortho2(xmin, xmax, ymin, ymax);
2535         }
2536         else myortho2(rectf->xmin, rectf->xmax, rectf->ymin, rectf->ymax);
2537         
2538         glSelectBuffer( MAXPICKBUF, buffer); 
2539         glRenderMode(GL_SELECT);
2540         glInitNames();  /* whatfor? but otherwise it does not work */
2541         glPushName(-1);
2542         
2543         /* get rid of buttons view */
2544         glPushMatrix();
2545         glLoadIdentity();
2546         
2547         init_pickselcode();     /* drawipo.c */
2548         draw_ipocurves(0);      
2549         
2550         /* restore buttons view */
2551         glPopMatrix();
2552
2553         G.f -= G_PICKSEL;
2554         
2555         hits= glRenderMode(GL_RENDER);
2556         glPopName();    /* see above (pushname) */
2557         if(hits<1) return 0;
2558         
2559         code= 1;
2560         ei= G.sipo->editipo;
2561         for(a=0; a<G.sipo->totipo; a++, ei++) {
2562                 if ISPOIN(ei, icu, flag & IPO_VISIBLE) {
2563                         if(rectf) {
2564                                 for(b=0; b<hits; b++) {
2565                                         /* conversion for glSelect */
2566                                         if(code == buffer[ (4 * b) + 3] ) {
2567                                                 if(event==LEFTMOUSE) ei->flag |= IPO_SELECT;
2568                                                 else ei->flag &= ~IPO_SELECT;
2569                                                 ei->icu->flag= ei->flag;
2570                                         }
2571                                 }
2572                         }
2573                         else {
2574                                 /* also conversion for glSelect */
2575                                 if(code==buffer[ 3 ]) return ei;
2576                         }
2577                         code++;
2578                 }
2579         }
2580         return 0;
2581 }
2582