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