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