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