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