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