4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
44 #include "MEM_guardedalloc.h"
46 #include "BLI_blenlib.h"
47 #include "BLI_arithb.h"
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"
60 #include "BKE_curve.h"
61 #include "BKE_depsgraph.h"
62 #include "BKE_global.h"
65 #include "BKE_object.h"
66 #include "BKE_utildefines.h"
68 #include "BIF_cursors.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"
82 #include "BSE_drawipo.h"
84 #include "BSE_editipo.h"
85 #include "BSE_editipo_types.h"
86 #include "BSE_editnla_types.h"
89 #ifndef DISABLE_PYTHON
90 #include "BPY_extern.h"
95 #include "butspace.h" // shouldnt be...
96 #include "interface.h" /* for ui_rasterpos_safe */
99 /* local define... also used in editipo ... */
100 #define ISPOIN(a, b, c) ( (a->b) && (a->c) )
101 #define ISPOIN3(a, b, c, d) ( (a->b) && (a->c) && (a->d) )
102 #define ISPOIN4(a, b, c, d, e) ( (a->b) && (a->c) && (a->d) && (a->e) )
104 /* minimum pixels per gridstep */
107 static float ipogrid_dx, ipogrid_dy, ipogrid_startx, ipogrid_starty;
108 static int ipomachtx, ipomachty;
110 static int vertymin, vertymax, horxmin, horxmax; /* globals to test LEFTMOUSE for scrollbar */
112 static void scroll_prstr(float x, float y, float val, char dir, int disptype)
119 if ELEM(disptype, IPO_DISPDEGR, IPO_DISPTIME) {
124 else macht= ipomachtx;
126 if (macht<=0) sprintf(str, "%.*f", 1-macht, val);
127 else sprintf(str, "%d", (int)floor(val + 0.375));
130 if(dir=='h') x-= 4*len;
132 if(dir=='v' && disptype==IPO_DISPDEGR) {
133 str[len]= 186; /* Degree symbol */
137 ui_rasterpos_safe(x, y, 1.0);
138 BIF_DrawString(G.fonts, str, 0);
141 static void step_to_grid(float *step, int *macht)
145 /* try to write step as a power of 10 */
154 if(rem < 0.2) rem= 0.2;
155 else if(rem < 0.5) rem= 0.5;
158 *step= rem*pow(10.0, (float)*macht);
160 // partial of a frame have no meaning
161 switch(curarea->spacetype) {
163 SpaceTime *stime= curarea->spacedata.first;
164 if(stime->flag & TIME_DRAWFRAMES) {
171 SpaceTime * sseq= curarea->spacedata.first;
172 if (sseq->flag & SEQ_DRAWFRAMES) {
183 if(rem==1.0) (*macht)++; // prevents printing 1.0 2.0 3.0 etc
186 if(rem < 2.0) rem= 2.0;
187 else if(rem < 5.0) rem= 5.0;
190 *step= rem*pow(10.0, (float)*macht);
193 if(rem==10.0) (*macht)++; // prevents printing 1.0 2.0 3.0 etc
199 float space, pixels, secondiv=1.0;
201 /* rule: gridstep is minimal IPOSTEP pixels */
202 /* how large is IPOSTEP pixels? */
206 /* detect of we have seconds or frames, should become argument */
208 switch(curarea->spacetype) {
210 SpaceTime *stime= curarea->spacedata.first;
211 if(!(stime->flag & TIME_DRAWFRAMES)) {
213 secondiv= 0.01 * FPS;
218 SpaceSeq * sseq = curarea->spacedata.first;
219 if (!(sseq->flag & SEQ_DRAWFRAMES)) {
221 secondiv = 0.01 * FPS;
226 SpaceAction *saction = curarea->spacedata.first;
227 if (saction->flag & SACTION_DRAWTIME) {
229 secondiv = 0.01 * FPS;
234 SpaceNla *snla = curarea->spacedata.first;
235 if (snla->flag & SNLA_DRAWTIME) {
237 secondiv = 0.01 * FPS;
245 space= G.v2d->cur.xmax - G.v2d->cur.xmin;
246 pixels= G.v2d->mask.xmax-G.v2d->mask.xmin;
248 ipogrid_dx= IPOSTEP*space/(secondiv*pixels);
249 step_to_grid(&ipogrid_dx, &ipomachtx);
250 ipogrid_dx*= secondiv;
252 if ELEM5(curarea->spacetype, SPACE_SEQ, SPACE_SOUND, SPACE_TIME, SPACE_ACTION, SPACE_NLA) {
253 if(ipogrid_dx < 0.1) ipogrid_dx= 0.1;
255 if(ipomachtx<-2) ipomachtx= -2;
258 space= (G.v2d->cur.ymax - G.v2d->cur.ymin);
259 pixels= curarea->winy;
260 ipogrid_dy= IPOSTEP*space/pixels;
261 step_to_grid(&ipogrid_dy, &ipomachty);
263 if ELEM5(curarea->spacetype, SPACE_SEQ, SPACE_SOUND, SPACE_TIME, SPACE_ACTION, SPACE_NLA) {
264 if(ipogrid_dy < 1.0) ipogrid_dy= 1.0;
265 if(ipomachty<1) ipomachty= 1;
268 ipogrid_startx= secondiv*(G.v2d->cur.xmin/secondiv - fmod(G.v2d->cur.xmin/secondiv, ipogrid_dx/secondiv));
269 if(G.v2d->cur.xmin<0.0) ipogrid_startx-= ipogrid_dx;
271 ipogrid_starty= (G.v2d->cur.ymin-fmod(G.v2d->cur.ymin, ipogrid_dy));
272 if(G.v2d->cur.ymin<0.0) ipogrid_starty-= ipogrid_dy;
276 void draw_ipogrid(void)
278 float vec1[2], vec2[2];
281 vec1[0]= vec2[0]= ipogrid_startx;
282 vec1[1]= ipogrid_starty;
283 vec2[1]= G.v2d->cur.ymax;
285 step= (G.v2d->mask.xmax-G.v2d->mask.xmin+1)/IPOSTEP;
287 BIF_ThemeColor(TH_GRID);
289 for(a=0; a<step; a++) {
290 glBegin(GL_LINE_STRIP);
291 glVertex2fv(vec1); glVertex2fv(vec2);
293 vec2[0]= vec1[0]+= ipogrid_dx;
296 vec2[0]= vec1[0]-= 0.5*ipogrid_dx;
298 BIF_ThemeColorShade(TH_GRID, 16);
301 for(a=0; a<=step; a++) {
302 glBegin(GL_LINE_STRIP);
303 glVertex2fv(vec1); glVertex2fv(vec2);
305 vec2[0]= vec1[0]-= ipogrid_dx;
308 if ELEM4(curarea->spacetype, SPACE_SOUND, SPACE_ACTION, SPACE_NLA, SPACE_TIME);
310 vec1[0]= ipogrid_startx;
311 vec1[1]= vec2[1]= ipogrid_starty;
312 vec2[0]= G.v2d->cur.xmax;
314 step= (curarea->winy+1)/IPOSTEP;
316 BIF_ThemeColor(TH_GRID);
317 for(a=0; a<=step; a++) {
318 glBegin(GL_LINE_STRIP);
319 glVertex2fv(vec1); glVertex2fv(vec2);
321 vec2[1]= vec1[1]+= ipogrid_dy;
323 vec2[1]= vec1[1]-= 0.5*ipogrid_dy;
326 if(curarea->spacetype==SPACE_IPO) {
327 BIF_ThemeColorShade(TH_GRID, 16);
328 for(a=0; a<step; a++) {
329 glBegin(GL_LINE_STRIP);
330 glVertex2fv(vec1); glVertex2fv(vec2);
332 vec2[1]= vec1[1]-= ipogrid_dy;
337 BIF_ThemeColorShade(TH_GRID, -50);
339 if (curarea->spacetype!=SPACE_ACTION && curarea->spacetype!=SPACE_NLA)
340 { /* Horizontal axis */
341 vec1[0]= G.v2d->cur.xmin;
342 vec2[0]= G.v2d->cur.xmax;
343 vec1[1]= vec2[1]= 0.0;
344 glBegin(GL_LINE_STRIP);
354 vec1[1]= G.v2d->cur.ymin;
355 vec2[1]= G.v2d->cur.ymax;
356 vec1[0]= vec2[0]= 0.0;
357 glBegin(GL_LINE_STRIP);
358 glVertex2fv(vec1); glVertex2fv(vec2);
362 if(curarea->spacetype==SPACE_IPO) {
363 if(G.sipo->blocktype==ID_SEQ) {
364 Sequence * last_seq = get_last_seq();
369 ((last_seq->flag & SEQ_IPO_FRAME_LOCKED) != 0)) {
370 start = last_seq->startdisp;
371 end = last_seq->enddisp;
374 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
375 glRectf(start, 0.0, end, 1.0);
376 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
378 else if(ELEM(G.sipo->blocktype, ID_CU, ID_CO)) {
379 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
380 glRectf(0.0, 1.0, G.v2d->cur.xmax, 1.0);
381 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
386 void areamouseco_to_ipoco(View2D *v2d, short *mval, float *x, float *y)
390 div= v2d->mask.xmax-v2d->mask.xmin;
393 *x= v2d->cur.xmin+ (v2d->cur.xmax-v2d->cur.xmin)*(mval[0]-ofs)/div;
395 div= v2d->mask.ymax-v2d->mask.ymin;
398 *y= v2d->cur.ymin+ (v2d->cur.ymax-v2d->cur.ymin)*(mval[1]-ofs)/div;
401 void ipoco_to_areaco(View2D *v2d, float *vec, short *mval)
407 x= (vec[0] - v2d->cur.xmin)/(v2d->cur.xmax-v2d->cur.xmin);
408 y= (vec[1] - v2d->cur.ymin)/(v2d->cur.ymax-v2d->cur.ymin);
410 if(x>=0.0 && x<=1.0) {
411 if(y>=0.0 && y<=1.0) {
412 mval[0]= v2d->mask.xmin + x*(v2d->mask.xmax-v2d->mask.xmin);
413 mval[1]= v2d->mask.ymin + y*(v2d->mask.ymax-v2d->mask.ymin);
418 void ipoco_to_areaco_noclip(View2D *v2d, float *vec, short *mval)
422 x= (vec[0] - v2d->cur.xmin)/(v2d->cur.xmax-v2d->cur.xmin);
423 y= (vec[1] - v2d->cur.ymin)/(v2d->cur.ymax-v2d->cur.ymin);
425 x= v2d->mask.xmin + x*(v2d->mask.xmax-v2d->mask.xmin);
426 y= v2d->mask.ymin + y*(v2d->mask.ymax-v2d->mask.ymin);
428 if(x<-32760) mval[0]= -32760;
429 else if(x>32760) mval[0]= 32760;
432 if(y<-32760) mval[1]= -32760;
433 else if(y>32760) mval[1]= 32760;
437 int in_ipo_buttons(void)
441 getmouseco_areawin(mval);
443 if(mval[0]< G.v2d->mask.xmax) return 0;
447 View2D *spacelink_get_view2d(SpaceLink *sl)
449 if(sl->spacetype==SPACE_IPO)
450 return &((SpaceIpo *)sl)->v2d;
451 else if(sl->spacetype==SPACE_SOUND)
452 return &((SpaceSound *)sl)->v2d;
453 if(sl->spacetype==SPACE_ACTION)
454 return &((SpaceAction *)sl)->v2d;
455 if(sl->spacetype==SPACE_NLA)
456 return &((SpaceNla *)sl)->v2d;
457 if(sl->spacetype==SPACE_TIME)
458 return &((SpaceTime *)sl)->v2d;
459 if(sl->spacetype==SPACE_SEQ)
460 return &((SpaceSeq *)sl)->v2d;
464 /* copies changes in this view from or to all 2d views with lock option open */
465 /* do not call this inside of drawing routines, to prevent eternal loops */
466 void view2d_do_locks(ScrArea *cursa, int flag)
469 View2D *v2d, *curv2d;
472 curv2d= spacelink_get_view2d(cursa->spacedata.first);
473 if(curv2d==NULL) return;
474 if((curv2d->flag & V2D_VIEWLOCK)==0) return;
476 for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
478 for(sl= sa->spacedata.first; sl; sl= sl->next) {
480 v2d= spacelink_get_view2d(sl);
482 if(v2d->flag & V2D_VIEWLOCK) {
483 if(flag & V2D_LOCK_COPY) {
484 v2d->cur.xmin= curv2d->cur.xmin;
485 v2d->cur.xmax= curv2d->cur.xmax;
488 curv2d->cur.xmin= v2d->cur.xmin;
489 curv2d->cur.xmax= v2d->cur.xmax;
490 scrarea_queue_winredraw(sa);
493 if(flag & V2D_LOCK_REDRAW) {
494 if(sl == sa->spacedata.first)
495 scrarea_do_windraw(sa);
498 scrarea_queue_winredraw(sa);
506 /* event based, note: curarea is in here... */
507 void view2d_zoom(View2D *v2d, float factor, int winx, int winy)
509 float dx= factor*(v2d->cur.xmax-v2d->cur.xmin);
510 float dy= factor*(v2d->cur.ymax-v2d->cur.ymin);
511 if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) {
515 if ((v2d->keepzoom & V2D_LOCKZOOM_Y)==0) {
519 test_view2d(v2d, winx, winy);
520 view2d_do_locks(curarea, V2D_LOCK_COPY);
523 void view2d_getscale(View2D *v2d, float *x, float *y) {
524 if (x) *x = (G.v2d->mask.xmax-G.v2d->mask.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
525 if (y) *y = (G.v2d->mask.ymax-G.v2d->mask.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
528 void test_view2d(View2D *v2d, int winx, int winy)
530 /* cur is not allowed to be larger than max, smaller than min, or outside of tot */
532 float dx, dy, temp, fac, zoom;
534 /* correct winx for scroll */
535 if(v2d->scroll & L_SCROLL) winx-= SCROLLB;
536 if(v2d->scroll & B_SCROLL) winy-= SCROLLH;
537 if(v2d->scroll & B_SCROLLO) winy-= SCROLLH; /* B_SCROLL and B_SCROLLO are basically same thing */
539 /* header completely closed window */
545 dx= cur->xmax-cur->xmin;
546 dy= cur->ymax-cur->ymin;
549 if (v2d->keepzoom & V2D_LOCKZOOM_Y)
550 v2d->cur.ymax=v2d->cur.ymin+((float)winy);
552 if (v2d->keepzoom & V2D_LOCKZOOM_X)
553 v2d->cur.xmax=v2d->cur.xmin+((float)winx);
557 zoom= ((float)winx)/dx;
559 if(zoom<v2d->minzoom || zoom>v2d->maxzoom) {
560 if(zoom<v2d->minzoom) fac= zoom/v2d->minzoom;
561 else fac= zoom/v2d->maxzoom;
564 temp= 0.5*(cur->xmax+cur->xmin);
566 cur->xmin= temp-0.5*dx;
567 cur->xmax= temp+0.5*dx;
570 zoom= ((float)winy)/dy;
572 if(zoom<v2d->minzoom || zoom>v2d->maxzoom) {
573 if(zoom<v2d->minzoom) fac= zoom/v2d->minzoom;
574 else fac= zoom/v2d->maxzoom;
577 temp= 0.5*(cur->ymax+cur->ymin);
578 cur->ymin= temp-0.5*dy;
579 cur->ymax= temp+0.5*dy;
583 if(dx<G.v2d->min[0]) {
585 temp= 0.5*(cur->xmax+cur->xmin);
586 cur->xmin= temp-0.5*dx;
587 cur->xmax= temp+0.5*dx;
589 else if(dx>G.v2d->max[0]) {
591 temp= 0.5*(cur->xmax+cur->xmin);
592 cur->xmin= temp-0.5*dx;
593 cur->xmax= temp+0.5*dx;
596 if(dy<G.v2d->min[1]) {
598 temp= 0.5*(cur->ymax+cur->ymin);
599 cur->ymin= temp-0.5*dy;
600 cur->ymax= temp+0.5*dy;
602 else if(dy>G.v2d->max[1]) {
604 temp= 0.5*(cur->ymax+cur->ymin);
605 cur->ymin= temp-0.5*dy;
606 cur->ymax= temp+0.5*dy;
610 if(v2d->keepaspect) {
611 short do_x=0, do_y=0;
613 /* when a window edge changes, the aspect ratio can't be used to
614 find which is the best new 'cur' rect. thats why it stores 'old' */
615 if(winx!=v2d->oldwinx) do_x= 1;
616 if(winy!=v2d->oldwiny) do_y= 1;
618 dx= (cur->ymax-cur->ymin)/(cur->xmax-cur->xmin);
619 dy= ((float)winy)/((float)winx);
621 if(do_x==do_y) { // both sizes change, ctrl+uparrow
622 if(do_x==1 && do_y==1) {
623 if( ABS(winx-v2d->oldwinx)>ABS(winy-v2d->oldwiny)) do_y= 0;
626 else if( dy > 1.0) do_x= 0; else do_x= 1;
630 if (v2d->keeptot == 2 && winx < v2d->oldwinx) {
631 /* This is a special hack for the outliner, to ensure that the
632 * outliner contents will not eventually get pushed out of view
633 * when shrinking the view.
635 cur->xmax -= cur->xmin;
639 /* portrait window: correct for x */
640 dx= cur->ymax-cur->ymin;
641 temp= (cur->xmax+cur->xmin);
643 cur->xmin= temp/2.0 - 0.5*dx/dy;
644 cur->xmax= temp/2.0 + 0.5*dx/dy;
648 dx= cur->xmax-cur->xmin;
649 temp= (cur->ymax+cur->ymin);
651 cur->ymin= temp/2.0 - 0.5*dy*dx;
652 cur->ymax= temp/2.0 + 0.5*dy*dx;
660 dx= cur->xmax-cur->xmin;
661 dy= cur->ymax-cur->ymin;
663 if(dx > tot->xmax-tot->xmin) {
664 if(v2d->keepzoom==0) {
665 if(cur->xmin<tot->xmin) cur->xmin= tot->xmin;
666 if(cur->xmax>tot->xmax) cur->xmax= tot->xmax;
669 if(cur->xmax < tot->xmax) {
670 dx= tot->xmax-cur->xmax;
674 else if(cur->xmin > tot->xmin) {
675 dx= cur->xmin-tot->xmin;
682 if(cur->xmin < tot->xmin) {
683 dx= tot->xmin-cur->xmin;
687 else if((v2d->keeptot!=2) && (cur->xmax > tot->xmax)) {
688 /* keeptot==2 is a special case for the outliner. see space.c, init_v2d_oops for details */
689 dx= cur->xmax-tot->xmax;
695 if(dy > tot->ymax-tot->ymin) {
696 if(v2d->keepzoom==0) {
697 if(cur->ymin<tot->ymin) cur->ymin= tot->ymin;
698 if(cur->ymax>tot->ymax) cur->ymax= tot->ymax;
701 if(cur->ymax < tot->ymax) {
702 dy= tot->ymax-cur->ymax;
706 else if(cur->ymin > tot->ymin) {
707 dy= cur->ymin-tot->ymin;
714 if(cur->ymin < tot->ymin) {
715 dy= tot->ymin-cur->ymin;
719 else if(cur->ymax > tot->ymax) {
720 dy= cur->ymax-tot->ymax;
729 static int calc_ipobuttonswidth(ScrArea *sa)
731 SpaceIpo *sipo= sa->spacedata.first;
733 int ipowidth = IPOBUTX;
737 /* default width when no space ipo or no channels */
738 if (sipo == NULL) return IPOBUTX;
739 if ((sipo->totipo==0) || (sipo->editipo==NULL)) return IPOBUTX;
743 for(a=0; a<sipo->totipo; a++, ei++) {
744 textwidth = BIF_GetStringWidth(G.font, ei->name, 0);
745 if (textwidth + 18 > ipowidth)
746 ipowidth = textwidth + 18;
752 void calc_scrollrcts(ScrArea *sa, View2D *v2d, int winx, int winy)
754 v2d->mask.xmin= v2d->mask.ymin= 0;
755 v2d->mask.xmax= winx;
756 v2d->mask.ymax= winy;
758 if(sa->spacetype==SPACE_ACTION) {
759 if(sa->winx > ACTWIDTH+50) {
760 v2d->mask.xmin+= ACTWIDTH;
761 v2d->hor.xmin+=ACTWIDTH;
764 else if(sa->spacetype==SPACE_NLA){
765 if(sa->winx > NLAWIDTH+50) {
766 v2d->mask.xmin+= NLAWIDTH;
767 v2d->hor.xmin+=NLAWIDTH;
770 else if(sa->spacetype==SPACE_IPO) {
771 int ipobutx = calc_ipobuttonswidth(sa);
773 v2d->mask.xmax-= ipobutx;
775 if(v2d->mask.xmax<ipobutx)
776 v2d->mask.xmax= winx;
780 if(v2d->scroll & L_SCROLL) {
781 v2d->vert= v2d->mask;
782 v2d->vert.xmax= SCROLLB;
783 v2d->mask.xmin= SCROLLB;
785 else if(v2d->scroll & R_SCROLL) {
786 v2d->vert= v2d->mask;
787 v2d->vert.xmin= v2d->vert.xmax-SCROLLB;
788 v2d->mask.xmax= v2d->vert.xmin;
791 if((v2d->scroll & B_SCROLL) || (v2d->scroll & B_SCROLLO)) {
793 v2d->hor.ymax= SCROLLH;
794 v2d->mask.ymin= SCROLLH;
796 else if(v2d->scroll & T_SCROLL) {
798 v2d->hor.ymin= v2d->hor.ymax-SCROLLH;
799 v2d->mask.ymax= v2d->hor.ymin;
804 /* draws a line in left vertical scrollbar at the given height */
805 static void draw_solution_line(View2D *v2d, float h)
810 vec[0]= v2d->cur.xmin;
812 ipoco_to_areaco(v2d, vec, mval);
813 if(mval[0]!=IS_CLIPPED) {
815 glVertex2f(v2d->vert.xmin, mval[1]);
816 glVertex2f(v2d->vert.xmax, mval[1]);
821 static void draw_solution(SpaceIpo *sipo)
823 View2D *v2d= &sipo->v2d;
827 if (!(v2d->scroll & VERT_SCROLL)) return;
830 for(a=0; a<sipo->totipo; a++, ei++) {
831 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
834 /* DISPBITS ipos have 'multiple' values. */
835 if(ei->disptype==IPO_DISPBITS) {
836 int b, val= ei->icu->curval;
840 draw_solution_line(v2d, b+1);
842 draw_solution_line(v2d, ei->icu->curval);
848 /* used for drawing timeline */
849 void draw_view2d_numbers_horiz(int drawframes)
851 float fac, fac2, dfac, val;
853 /* the numbers: convert ipogrid_startx and -dx to scroll coordinates */
855 fac= (ipogrid_startx- G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
856 fac= G.v2d->mask.xmin+fac*(G.v2d->mask.xmax-G.v2d->mask.xmin);
858 dfac= (ipogrid_dx)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
859 dfac= dfac*(G.v2d->mask.xmax-G.v2d->mask.xmin);
861 BIF_ThemeColor(TH_TEXT);
863 while(fac < G.v2d->mask.xmax) {
867 scroll_prstr(fac, 2.0+(float)(G.v2d->mask.ymin), val, 'h', 0);
871 scroll_prstr(fac, 2.0+(float)(G.v2d->mask.ymin), fac2, 'h', 0);
880 void drawscroll(int disptype)
883 float fac, dfac, val, fac2, tim;
884 int darker, dark, light, lighter;
894 if((G.v2d->scroll & HOR_SCROLL) || (G.v2d->scroll & HOR_SCROLLO)) {
896 BIF_ThemeColorShade(TH_SHADE1, light);
897 glRecti(hor.xmin, hor.ymin, hor.xmax, hor.ymax);
900 fac= (G.v2d->cur.xmin- G.v2d->tot.xmin)/(G.v2d->tot.xmax-G.v2d->tot.xmin);
901 if(fac<0.0) fac= 0.0;
902 horxmin= hor.xmin+fac*(hor.xmax-hor.xmin);
904 fac= (G.v2d->cur.xmax- G.v2d->tot.xmin)/(G.v2d->tot.xmax-G.v2d->tot.xmin);
905 if(fac>1.0) fac= 1.0;
906 horxmax= hor.xmin+fac*(hor.xmax-hor.xmin);
908 if(horxmin > horxmax) horxmin= horxmax;
910 BIF_ThemeColorShade(TH_SHADE1, dark);
911 glRecti(horxmin, hor.ymin, horxmax, hor.ymax);
913 /* decoration bright line */
914 BIF_ThemeColorShade(TH_SHADE1, lighter);
915 sdrawline(hor.xmin, hor.ymax, hor.xmax, hor.ymax);
917 /* the numbers: convert ipogrid_startx and -dx to scroll coordinates */
918 fac= (ipogrid_startx- G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
919 fac= hor.xmin+fac*(hor.xmax-hor.xmin);
921 dfac= (ipogrid_dx)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
922 dfac= dfac*(hor.xmax-hor.xmin);
924 BIF_ThemeColor(TH_TEXT);
927 if (ELEM3(curarea->spacetype, SPACE_SEQ, SPACE_SOUND, SPACE_TIME)) { /* prevents printing twice same frame */
928 while(ipogrid_dx < 0.9999f) {
933 while(fac < hor.xmax) {
935 if(curarea->spacetype==SPACE_OOPS) {
936 /* Under no circumstances may the outliner/oops display numbers on its scrollbar
937 * Unfortunately, versions of Blender without this patch will hang on loading files with
938 * horizontally scrollable Outliners.
942 else if(curarea->spacetype==SPACE_SEQ) {
943 SpaceSeq * sseq = curarea->spacedata.first;
944 if (sseq->flag & SEQ_DRAWFRAMES) {
946 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
951 scroll_prstr(fac, 3.0+(float)(hor.ymin), tim+FPS*fac2/100.0, 'h', disptype);
954 else if (curarea->spacetype==SPACE_SOUND) {
955 SpaceSound *ssound= curarea->spacedata.first;
957 if(ssound->flag & SND_DRAWFRAMES) {
959 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
963 scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
966 else if (curarea->spacetype==SPACE_TIME) {
967 SpaceTime *stime= curarea->spacedata.first;
969 if(stime->flag & TIME_DRAWFRAMES) {
971 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
975 scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
978 else if (curarea->spacetype==SPACE_IPO) {
979 EditIpo *ei= get_active_editipo();
981 if(ei && ei->icu && ei->icu->driver) {
982 int adrcode= ei->icu->driver->adrcode;
984 if(adrcode==OB_ROT_X || adrcode==OB_ROT_Y || adrcode==OB_ROT_Z) {
985 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'v', IPO_DISPDEGR);
988 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
991 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
993 else if (curarea->spacetype==SPACE_ACTION) {
994 SpaceAction *saction= curarea->spacedata.first;
996 if (saction->flag & SACTION_DRAWTIME) {
998 scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
1002 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
1005 else if (curarea->spacetype==SPACE_NLA) {
1006 SpaceNla *snla= curarea->spacedata.first;
1008 if (snla->flag & SNLA_DRAWTIME) {
1010 scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
1014 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
1018 scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
1026 if(G.v2d->scroll & VERT_SCROLL) {
1027 BIF_ThemeColorShade(TH_SHADE1, light);
1028 glRecti(vert.xmin, vert.ymin, vert.xmax, vert.ymax);
1031 fac= (G.v2d->cur.ymin- G.v2d->tot.ymin)/(G.v2d->tot.ymax-G.v2d->tot.ymin);
1032 if(fac<0.0) fac= 0.0;
1033 vertymin= vert.ymin+fac*(vert.ymax-vert.ymin);
1035 fac= (G.v2d->cur.ymax- G.v2d->tot.ymin)/(G.v2d->tot.ymax-G.v2d->tot.ymin);
1036 if(fac>1.0) fac= 1.0;
1037 vertymax= vert.ymin+fac*(vert.ymax-vert.ymin);
1039 if(vertymin > vertymax) vertymin= vertymax;
1041 BIF_ThemeColorShade(TH_SHADE1, dark);
1042 glRecti(vert.xmin, vertymin, vert.xmax, vertymax);
1044 /* decoration black line */
1045 BIF_ThemeColorShade(TH_SHADE1, darker);
1046 if(G.v2d->scroll & HOR_SCROLL)
1047 sdrawline(vert.xmax, vert.ymin+SCROLLH, vert.xmax, vert.ymax);
1049 sdrawline(vert.xmax, vert.ymin, vert.xmax, vert.ymax);
1051 /* the numbers: convert ipogrid_starty and -dy to scroll coordinates */
1052 fac= (ipogrid_starty- G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
1053 fac= vert.ymin+SCROLLH+fac*(vert.ymax-vert.ymin-SCROLLH);
1055 dfac= (ipogrid_dy)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
1056 dfac= dfac*(vert.ymax-vert.ymin-SCROLLH);
1058 if(curarea->spacetype==SPACE_OOPS);
1059 else if(curarea->spacetype==SPACE_SEQ) {
1060 BIF_ThemeColor(TH_TEXT);
1061 val= ipogrid_starty;
1063 while(fac < vert.ymax) {
1064 scroll_prstr((float)(vert.xmax)-14.0, fac, val, 'v', disptype);
1069 else if (curarea->spacetype==SPACE_NLA){
1071 else if (curarea->spacetype==SPACE_ACTION){
1072 /* No digits on vertical axis in action mode! */
1075 BIF_ThemeColor(TH_TEXT);
1076 val= ipogrid_starty;
1077 while(fac < vert.ymax) {
1078 scroll_prstr((float)(vert.xmax)-14.0, fac, val, 'v', disptype);
1086 static void draw_ipobuts(SpaceIpo *sipo)
1088 ScrArea *area= sipo->area;
1089 View2D *v2d= &sipo->v2d;
1094 int a, y, sel, tot, ipobutx;
1097 if(area->winx< calc_ipobuttonswidth(area)) return;
1100 tot= 30+IPOBUTY*sipo->totipo;
1101 if(tot<area->winy) sipo->butofs= 0;
1104 ipobutx = calc_ipobuttonswidth(area);
1106 BIF_ThemeColor(TH_SHADE2);
1107 glRects(v2d->mask.xmax, 0, area->winx, area->winy);
1110 sdrawline(v2d->mask.xmax, 0, v2d->mask.xmax, area->winy);
1112 if(sipo->totipo==0) return;
1113 if(sipo->editipo==0) return;
1115 sprintf(naam, "ipowin %d", area->win);
1116 block= uiNewBlock(&area->uiblocks, naam, UI_EMBOSSN, UI_HELV, area->win);
1119 y= area->winy-30+sipo->butofs;
1121 if(ob && sipo->blocktype==ID_KE) {
1123 if(ob->shapeflag & OB_SHAPE_LOCK) icon= ICON_PIN_HLT; else icon= ICON_PIN_DEHLT;
1124 uiDefIconButBitS(block, TOG, OB_SHAPE_LOCK, B_SETKEY, icon,
1125 v2d->mask.xmax+18,y,25,20, &ob->shapeflag, 0, 0, 0, 0, "Always show the current Shape for this Object");
1129 for(a=0; a<sipo->totipo; a++, ei++, y-=IPOBUTY) {
1130 // this button defines visiblity, bit zero of flag (IPO_VISIBLE)
1131 but= uiDefButBitS(block, TOG, IPO_VISIBLE, a+1, ei->name, v2d->mask.xmax+18, y, ipobutx-15, IPOBUTY-1, &(ei->flag), 0, 0, 0, 0, "");
1132 // no hilite, its not visible, but most of all the winmatrix is not correct later on...
1133 uiButSetFlag(but, UI_TEXT_LEFT|UI_NO_HILITE);
1135 // this fake button defines selection of curves
1139 glRects(v2d->mask.xmax+8, y+2, v2d->mask.xmax+15, y+IPOBUTY-2);
1140 sel= ei->flag & (IPO_SELECT + IPO_EDIT);
1142 uiEmboss((float)(v2d->mask.xmax+8), (float)(y+2), (float)(v2d->mask.xmax+15), (float)(y+IPOBUTY-2), sel);
1144 if(ei->icu->driver) {
1146 fdrawbox((float)v2d->mask.xmax+11, (float)y+8, (float)v2d->mask.xmax+12.5, (float)y+9.5);
1150 if(ei->flag & IPO_ACTIVE) {
1152 fdrawbox(v2d->mask.xmax+7, y+1, v2d->mask.xmax+16, y+IPOBUTY-1);
1158 static void draw_ipovertices(int sel)
1163 int val, ok, nr, a, b;
1165 if(G.f & G_PICKSEL) return;
1167 glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
1169 ei= G.sipo->editipo;
1170 for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
1171 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
1173 if(G.sipo->showkey) {
1174 if(sel) BIF_ThemeColor(TH_TEXT_HI);
1175 else BIF_ThemeColor(TH_TEXT);
1176 } else if(ei->flag & IPO_EDIT) {
1177 if(sel) BIF_ThemeColor(TH_VERTEX_SELECT);
1178 else BIF_ThemeColor(TH_VERTEX);
1180 if(sel) BIF_ThemeColor(TH_TEXT_HI);
1181 else BIF_ThemeColor(TH_TEXT);
1183 val= (ei->icu->flag & IPO_SELECT)!=0;
1184 if(sel != val) continue;
1187 /* We can't change the color in the middle of
1188 * GL_POINTS because then Blender will segfault
1189 * on TNT2 / Linux with NVidia's drivers
1190 * (at least up to ver. 4349) */
1192 a= ei->icu->totvert;
1193 bezt= ei->icu->bezt;
1194 bglBegin(GL_POINTS);
1198 /* IPO_DISPBITS is used for displaying layer ipo types as well as modes */
1199 if(ei->disptype==IPO_DISPBITS) {
1200 /*if (G.v2d->cur.xmin < bezt->vec[1][0] < G.v2d->cur.xmax) {*/
1203 if(ei->flag & IPO_EDIT) {
1204 if( (bezt->f2 & SELECT) == sel ) ok= 1;
1209 val= bezt->vec[1][1];
1211 v1[0]= bezt->vec[1][0];
1222 } else { /* normal non bit curves */
1223 if(ei->flag & IPO_EDIT) {
1224 /* Only the vertex of the line, the
1225 * handler are draw below.
1227 if( (bezt->f2 & SELECT) == sel) /* && G.v2d->cur.xmin < bezt->vec[1][0] < G.v2d->cur.xmax)*/
1228 bglVertex3fv(bezt->vec[1]);
1232 /* draw only if in bounds */
1233 /*if (G.v2d->cur.xmin < bezt->vec[1][0] < G.v2d->cur.xmax)*/
1234 bglVertex3fv(bezt->vec[1]);
1243 if (ei->flag & IPO_EDIT) {
1244 /* Now draw the two vertex of the handler,
1245 * need split it because we can't call glPointSize
1246 * in the middle of a glBegin/glEnd also the
1247 * bug comment before.
1249 a= ei->icu->totvert;
1250 bezt= ei->icu->bezt;
1252 glPointSize(BIF_GetThemeValuef(TH_HANDLE_VERTEX_SIZE));
1254 if(sel) BIF_ThemeColor(TH_HANDLE_VERTEX_SELECT);
1255 else BIF_ThemeColor(TH_HANDLE_VERTEX);
1257 bglBegin(GL_POINTS);
1260 if (ei->disptype!=IPO_DISPBITS) {
1261 if(ei->flag & IPO_EDIT) {
1262 if(ei->icu->ipo==IPO_BEZ) {
1263 /* Draw the editmode hendels for a bezier curve */
1264 if( (bezt->f1 & SELECT) == sel)/* && G.v2d->cur.xmin < bezt->vec[0][0] < G.v2d->cur.xmax)*/
1265 bglVertex3fv(bezt->vec[0]);
1267 if( (bezt->f3 & SELECT) == sel)/* && G.v2d->cur.xmin < bezt->vec[2][0] < G.v2d->cur.xmax)*/
1268 bglVertex3fv(bezt->vec[2]);
1276 /* The color are always reset (see the while)
1277 * but the point size not so we reset now.
1279 glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
1287 static void draw_ipohandles(int sel)
1289 extern unsigned int nurbcol[];
1296 if(sel) col= nurbcol+4;
1299 ei= G.sipo->editipo;
1300 for(a=0; a<G.sipo->totipo; a++, ei++) {
1301 if ISPOIN4(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu, disptype!=IPO_DISPBITS) {
1302 if(ei->icu->ipo==IPO_BEZ) {
1303 bezt= ei->icu->bezt;
1304 b= ei->icu->totvert;
1307 if( (bezt->f2 & SELECT)==sel) {
1309 cpack(col[bezt->h1]);
1311 glBegin(GL_LINE_STRIP);
1312 glVertex2fv(fp); glVertex2fv(fp+3);
1314 cpack(col[bezt->h2]);
1316 glBegin(GL_LINE_STRIP);
1317 glVertex2fv(fp+3); glVertex2fv(fp+6);
1320 else if( (bezt->f1 & SELECT)==sel) {
1322 cpack(col[bezt->h1]);
1324 glBegin(GL_LINE_STRIP);
1325 glVertex2fv(fp); glVertex2fv(fp+3);
1328 else if( (bezt->f3 & SELECT)==sel) {
1330 cpack(col[bezt->h2]);
1332 glBegin(GL_LINE_STRIP);
1333 glVertex2fv(fp); glVertex2fv(fp+3);
1346 static void init_pickselcode(void)
1351 static void draw_ipocurves(int sel)
1355 BezTriple *bezt, *prevbezt;
1356 float *fp, fac, data[120], v1[2], v2[2], v3[2], v4[2];
1357 float cycdx=0, cycdy=0, cycxofs, cycyofs;
1358 int a, b, resol, cycount, val, nr;
1361 ei= G.sipo->editipo;
1362 for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
1363 if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) {
1365 if(G.f & G_PICKSEL) {
1366 glLoadName(pickselcode++);
1370 val= (ei->flag & (IPO_SELECT+IPO_EDIT))!=0;
1376 cycyofs= cycxofs= 0.0;
1382 if(G.sipo->showkey) BIF_ThemeColor(TH_TEXT);
1383 else cpack(ei->col);
1386 if(icu->extrap & IPO_CYCL) {
1387 cycdx= (icu->bezt+icu->totvert-1)->vec[1][0] - icu->bezt->vec[1][0];
1388 cycdy= (icu->bezt+icu->totvert-1)->vec[1][1] - icu->bezt->vec[1][1];
1391 while(icu->bezt->vec[1][0]+cycxofs > G.v2d->cur.xmin) {
1393 if(icu->extrap & IPO_DIR) cycyofs-= cycdy;
1396 bezt= icu->bezt+(icu->totvert-1);
1398 while(bezt->vec[1][0]+fac < G.v2d->cur.xmax) {
1407 if(ei->disptype==IPO_DISPBITS) {
1415 val= bezt->vec[1][1];
1422 glBegin(GL_LINE_STRIP);
1423 if(icu->extrap & IPO_CYCL) ;
1424 else if(a==icu->totvert-1) {
1425 v1[0]= G.v2d->cur.xmin+cycxofs;
1428 v1[0]= bezt->vec[1][0]+cycxofs;
1431 if(a) v1[0]= (bezt+1)->vec[1][0]+cycxofs;
1432 else if(icu->extrap & IPO_CYCL) ;
1433 else v1[0]= G.v2d->cur.xmax+cycxofs;
1447 prevbezt= icu->bezt;
1450 glBegin(GL_LINE_STRIP);
1452 /* extrapolate to left? */
1453 if( (icu->extrap & IPO_CYCL)==0) {
1454 if(prevbezt->vec[1][0] > G.v2d->cur.xmin) {
1455 v1[0]= G.v2d->cur.xmin;
1456 if(icu->extrap==IPO_HORIZ || icu->ipo==IPO_CONST || icu->totvert==1) {
1457 v1[1]= prevbezt->vec[1][1];
1458 } else if (icu->ipo==IPO_LIN) {
1459 /* extrapolate linear dosnt use the handle, use the next points center instead */
1460 fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
1461 if(fac!=0.0) fac= 1.0/fac;
1462 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]);
1464 fac= (prevbezt->vec[0][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
1465 if(fac!=0.0) fac= 1.0/fac;
1466 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[0][1]-prevbezt->vec[1][1]);
1473 v1[0]= prevbezt->vec[1][0]+cycxofs;
1474 v1[1]= prevbezt->vec[1][1]+cycyofs;
1479 if(icu->ipo==IPO_CONST) {
1480 v1[0]= prevbezt->vec[1][0]+cycxofs;
1481 v1[1]= prevbezt->vec[1][1]+cycyofs;
1483 v1[0]= bezt->vec[1][0]+cycxofs;
1484 v1[1]= prevbezt->vec[1][1]+cycyofs;
1487 else if(icu->ipo==IPO_LIN) {
1488 v1[0]= prevbezt->vec[1][0]+cycxofs;
1489 v1[1]= prevbezt->vec[1][1]+cycyofs;
1493 /* resol not depending on horizontal resolution anymore, drivers for example... */
1494 if(icu->driver) resol= 32;
1495 else resol= 3.0*sqrt(bezt->vec[1][0] - prevbezt->vec[1][0]);
1498 v1[0]= prevbezt->vec[1][0]+cycxofs;
1499 v1[1]= prevbezt->vec[1][1]+cycyofs;
1503 if(resol>32) resol= 32;
1505 v1[0]= prevbezt->vec[1][0]+cycxofs;
1506 v1[1]= prevbezt->vec[1][1]+cycyofs;
1507 v2[0]= prevbezt->vec[2][0]+cycxofs;
1508 v2[1]= prevbezt->vec[2][1]+cycyofs;
1510 v3[0]= bezt->vec[0][0]+cycxofs;
1511 v3[1]= bezt->vec[0][1]+cycyofs;
1512 v4[0]= bezt->vec[1][0]+cycxofs;
1513 v4[1]= bezt->vec[1][1]+cycyofs;
1515 correct_bezpart(v1, v2, v3, v4);
1517 forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, 3);
1518 forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data+1, resol, 3);
1532 v1[0]= prevbezt->vec[1][0]+cycxofs;
1533 v1[1]= prevbezt->vec[1][1]+cycyofs;
1538 /* extrapolate to right? */
1539 if( (icu->extrap & IPO_CYCL)==0) {
1540 if(prevbezt->vec[1][0] < G.v2d->cur.xmax) {
1541 v1[0]= G.v2d->cur.xmax;
1542 if(icu->extrap==IPO_HORIZ || icu->ipo==IPO_CONST ||icu->totvert==1) {
1543 v1[1]= prevbezt->vec[1][1];
1544 } else if (icu->ipo==IPO_LIN) {
1545 /* extrapolate linear dosnt use the handle, use the previous points center instead */
1547 fac= (prevbezt->vec[1][0]-bezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
1548 if(fac!=0.0) fac= 1.0/fac;
1549 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[1][1]-bezt->vec[1][1]);
1551 fac= (prevbezt->vec[2][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
1552 if(fac!=0.0) fac= 1.0/fac;
1553 v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[2][1]-prevbezt->vec[1][1]);
1563 if(icu->extrap & IPO_DIR) cycyofs+= cycdy;
1566 /* line that indicates the end of a speed curve */
1567 if(G.sipo->blocktype==ID_CU && icu->adrcode==CU_SPEED) {
1570 glColor3ub(0, 0, 0);
1573 glVertex2f(bezt->vec[1][0], 0.0);
1574 glVertex2f(bezt->vec[1][0], bezt->vec[1][1]);
1583 static int get_ipo_cfra_from_cfra(SpaceIpo * sipo, int cfra)
1585 if (sipo->blocktype==ID_SEQ) {
1586 Sequence * seq = (Sequence*) sipo->from;
1592 if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
1595 float ctime= frame_to_float(cfra - seq->startdisp);
1596 float div= (seq->enddisp - seq->startdisp)/100.0f;
1609 static void draw_cfra(SpaceIpo *sipo)
1611 View2D *v2d= &sipo->v2d;
1615 vec[0] = get_ipo_cfra_from_cfra(sipo, G.scene->r.cfra);
1616 vec[0]*= G.scene->r.framelen;
1618 vec[1]= v2d->cur.ymin;
1619 BIF_ThemeColor(TH_CFRAME);
1622 glBegin(GL_LINE_STRIP);
1624 vec[1]= v2d->cur.ymax;
1628 if(sipo->blocktype==ID_OB) {
1629 ob= (G.scene->basact) ? (G.scene->basact->object) : 0;
1630 if (ob && (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)!=0.0)) {
1631 vec[0]-= give_timeoffset(ob);
1633 BIF_ThemeColorShade(TH_HILITE, -30);
1635 glBegin(GL_LINE_STRIP);
1637 vec[1]= G.v2d->cur.ymin;
1646 static void draw_ipokey(SpaceIpo *sipo)
1651 for (ik= sipo->ipokey.first; ik; ik= ik->next) {
1652 if(ik->flag & 1) glColor3ub(0xFF, 0xFF, 0x99);
1653 else glColor3ub(0xAA, 0xAA, 0x55);
1655 glVertex2f(ik->val, G.v2d->cur.ymin);
1656 glVertex2f(ik->val, G.v2d->cur.ymax);
1661 static void draw_key(SpaceIpo *sipo, int visible)
1663 View2D *v2d= &sipo->v2d;
1665 KeyBlock *kb, *act=NULL;
1670 key= ob_get_key((Object *)sipo->from);
1674 if(key->type== KEY_RELATIVE) if(visible==0) return;
1676 for(index=1, kb= key->block.first; kb; kb= kb->next, index++) {
1677 if(kb->type==KEY_LINEAR) setlinestyle(2);
1678 else if(kb->type==KEY_BSPLINE) setlinestyle(4);
1679 else setlinestyle(0);
1681 if(kb==key->refkey) col= 0x22FFFF;
1684 if(ob->shapenr!=index) col-= 0x225500;
1689 glBegin(GL_LINE_STRIP);
1690 glVertex2f(v2d->cur.xmin, kb->pos);
1691 glVertex2f(v2d->cur.xmax, kb->pos);
1697 if(act->type==KEY_LINEAR) setlinestyle(2);
1698 else if(act->type==KEY_BSPLINE) setlinestyle(4);
1699 else setlinestyle(0);
1701 if(act==key->refkey) cpack(0x22FFFF);
1702 else cpack(0xFFFF00);
1704 glBegin(GL_LINE_STRIP);
1705 glVertex2f(v2d->cur.xmin, act->pos);
1706 glVertex2f(v2d->cur.xmax, act->pos);
1713 /* ************************** buttons *********************** */
1716 #define B_SETSPEED 3401
1717 #define B_MUL_IPO 3402
1718 #define B_TRANS_IPO 3403
1719 #define B_IPO_NONE 3404
1720 #define B_IPO_DRIVER 3405
1721 #define B_IPO_REDR 3406
1722 #define B_IPO_DEPCHANGE 3407
1723 #define B_IPO_DRIVERTYPE 3408
1725 static float hspeed= 0;
1727 static void boundbox_ipo_curves(SpaceIpo *si)
1738 for(a=0; a<si->totipo; a++, ei++) {
1741 if(ei->flag & IPO_VISIBLE) {
1743 boundbox_ipocurve(ei->icu, 0);
1745 si->v2d.tot= ei->icu->totrct;
1748 else BLI_union_rctf(&(si->v2d.tot), &(ei->icu->totrct));
1753 if(si->blocktype==ID_KE) {
1754 key= ob_get_key((Object *)si->from);
1755 if(key && key->block.first) {
1756 kb= key->block.first;
1757 if(kb->pos < si->v2d.tot.ymin) si->v2d.tot.ymin= kb->pos;
1758 kb= key->block.last;
1759 if(kb->pos > si->v2d.tot.ymax) si->v2d.tot.ymax= kb->pos;
1762 si->tot= si->v2d.tot;
1766 /* is used for both read and write... */
1767 static void ipo_editvertex_buts(uiBlock *block, SpaceIpo *si, float min, float max)
1773 int a, b, tot, iskey=0;
1775 median[0]= median[1]= median[2]= 0.0;
1778 /* use G.sipo->from (which should be an object) so that pinning ipo's will still work ok */
1779 if((G.sipo->from) && (GS(G.sipo->from->name) == ID_OB))
1780 ob= (Object *)(G.sipo->from);
1784 ei= G.sipo->editipo;
1785 for(a=0; a<G.sipo->totipo; a++, ei++) {
1787 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
1788 if( (ei->flag & IPO_EDIT) || G.sipo->showkey) {
1791 bezt= ei->icu->bezt;
1792 b= ei->icu->totvert;
1794 // all three selected
1795 if(bezt->f2 & SELECT) {
1796 VecAddf(median, median, bezt->vec[1]);
1800 if(bezt->f1 & SELECT) {
1801 VecAddf(median, median, bezt->vec[0]);
1804 if(bezt->f3 & SELECT) {
1805 VecAddf(median, median, bezt->vec[2]);
1816 /* check for keys */
1818 if(G.sipo->blocktype==ID_KE) {
1819 Key *key= ob_get_key((Object *)G.sipo->from);
1822 if(key==NULL || ob->shapenr==0) return;
1825 kb= BLI_findlink(&key->block, ob->shapenr-1);
1826 median[1]+= kb->pos;
1832 median[0] /= (float)tot;
1833 median[1] /= (float)tot;
1834 median[2] /= (float)tot;
1836 if(block) { // buttons
1838 VECCOPY(si->median, median);
1840 uiBlockBeginAlign(block);
1843 uiDefButF(block, NUM, B_TRANS_IPO, "Key Y:", 10, 80, 300, 19, &(si->median[1]), min, max, 10, 0, "");
1845 uiDefButF(block, NUM, B_TRANS_IPO, "Vertex X:", 10, 100, 150, 19, &(si->median[0]), min, max, 100, 0, "");
1846 uiDefButF(block, NUM, B_TRANS_IPO, "Vertex Y:", 160, 100, 150, 19, &(si->median[1]), min, max, 100, 0, "");
1851 uiDefButF(block, NUM, B_TRANS_IPO, "Median Key Y:", 10, 80, 300, 19, &(si->median[1]), min, max, 10, 0, "");
1853 uiDefButF(block, NUM, B_TRANS_IPO, "Median X:", 10, 100, 150, 19, &(si->median[0]), min, max, 100, 0, "");
1854 uiDefButF(block, NUM, B_TRANS_IPO, "Median Y:", 160, 100, 150, 19, &(si->median[1]), min, max, 100, 0, "");
1858 else if(iskey) { // apply
1859 VecSubf(median, si->median, median);
1861 if(G.sipo->blocktype==ID_KE) {
1862 Key *key= ob_get_key((Object *)G.sipo->from);
1865 if(key==NULL || ob->shapenr==0) return;
1867 kb= BLI_findlink(&key->block, ob->shapenr-1);
1868 kb->pos+= median[1];
1876 VecSubf(median, si->median, median);
1878 ei= G.sipo->editipo;
1879 for(a=0; a<G.sipo->totipo; a++, ei++) {
1881 if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
1882 if( (ei->flag & IPO_EDIT) || G.sipo->showkey) {
1885 bezt= ei->icu->bezt;
1886 b= ei->icu->totvert;
1888 // all three selected
1889 if(bezt->f2 & SELECT) {
1890 VecAddf(bezt->vec[0], bezt->vec[0], median);
1891 VecAddf(bezt->vec[1], bezt->vec[1], median);
1892 VecAddf(bezt->vec[2], bezt->vec[2], median);
1895 if(bezt->f1 & SELECT) {
1896 VecAddf(bezt->vec[0], bezt->vec[0], median);
1898 if(bezt->f3 & SELECT) {
1899 VecAddf(bezt->vec[2], bezt->vec[2], median);
1912 void do_ipobuts(unsigned short event)
1917 if(G.sipo->from==NULL) return;
1919 /* use G.sipo->from (which should be an object) so that pinning ipo's will still work ok */
1920 if(GS(G.sipo->from->name) == ID_OB)
1921 ob= (Object *)(G.sipo->from);
1927 ei= get_active_editipo();
1929 if(ei->icu->driver) {
1930 #ifndef DISABLE_PYTHON
1931 if (ei->icu->driver->type == IPO_DRIVER_TYPE_PYTHON) {
1932 /* first del pydriver's global dict, just in case
1933 * an available pydrivers.py module needs to be reloaded */
1934 BPY_pydriver_update();
1935 /* eval user's expression once for validity; update DAG */
1936 BPY_pydriver_eval(ei->icu->driver);
1937 DAG_scene_sort(G.scene);
1941 if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC)
1942 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
1944 DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
1947 allqueue(REDRAWIPO, 0);
1948 allqueue(REDRAWVIEW3D, 0);
1951 set_speed_editipo(hspeed);
1955 allqueue(REDRAWIPO, 0);
1958 ipo_editvertex_buts(NULL, G.sipo, 0.0, 0.0);
1959 editipo_changed(G.sipo, 1);
1960 allqueue(REDRAWIPO, 0);
1963 ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
1964 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
1965 allqueue(REDRAWVIEW3D, 0);
1966 allqueue(REDRAWIPO, 0);
1967 allqueue(REDRAWBUTSEDIT, 0);
1970 ei= get_active_editipo();
1973 ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, G.sipo->bonename, ei->adrcode, 1);
1975 error("Could not add a driver to this curve, may be linked data!");
1978 ei->flag |= IPO_SELECT;
1979 ei->icu->flag= ei->flag;
1981 if(ei->icu->driver) {
1982 MEM_freeN(ei->icu->driver);
1983 ei->icu->driver= NULL;
1984 if(ei->icu->bezt==NULL) {
1985 BLI_remlink( &(G.sipo->ipo->curve), ei->icu);
1986 free_ipo_curve(ei->icu);
1991 ei->icu->driver= MEM_callocN(sizeof(IpoDriver), "ipo driver");
1992 ei->icu->driver->blocktype= ID_OB;
1993 ei->icu->driver->adrcode= OB_LOC_X;
1996 allqueue(REDRAWVIEW3D, 0);
1997 allqueue(REDRAWIPO, 0);
1998 allqueue(REDRAWBUTSEDIT, 0);
1999 DAG_scene_sort(G.scene);
2001 BIF_undo_push("Add/Remove Ipo driver");
2004 case B_IPO_DRIVERTYPE:
2005 ei= get_active_editipo();
2007 if(ei->icu->driver) {
2008 IpoDriver *driver= ei->icu->driver;
2010 if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
2011 /* pydriver expression shouldn't reference own ob,
2012 * so we need to store ob ptr to check against it */
2017 driver->blocktype= ID_OB;
2018 driver->adrcode= OB_LOC_X;
2019 driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
2022 allqueue(REDRAWVIEW3D, 0);
2023 allqueue(REDRAWIPO, 0);
2024 allqueue(REDRAWBUTSEDIT, 0);
2025 DAG_scene_sort(G.scene);
2027 BIF_undo_push("Change Ipo driver type");
2030 case B_IPO_DEPCHANGE:
2031 ei= get_active_editipo();
2033 if(ei->icu->driver) {
2034 IpoDriver *driver= ei->icu->driver;
2036 if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
2040 if(ob==driver->ob && G.sipo->bonename[0]==0) {
2041 error("Cannot assign a Driver to own Object");
2045 /* check if type is still OK */
2046 if(driver->ob->type==OB_ARMATURE && driver->blocktype==ID_AR);
2047 else driver->blocktype= ID_OB;
2051 DAG_scene_sort(G.scene);
2053 if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC)
2054 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
2056 DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
2059 allqueue(REDRAWVIEW3D, 0);
2060 allqueue(REDRAWIPO, 0);
2061 allqueue(REDRAWBUTSEDIT, 0);
2066 static char *ipodriver_modeselect_pup(Object *ob)
2068 static char string[265];
2070 char formatstring[64];
2072 strcpy(string, "Driver type: %t");
2074 strcpy(formatstring, "|%s %%x%d %%i%d");
2077 sprintf(tmpstr,formatstring,"Object",ID_OB, ICON_OBJECT);
2078 strcat(string,tmpstr);
2080 if(ob && ob->type==OB_ARMATURE) {
2081 sprintf(tmpstr,formatstring,"Pose",ID_AR, ICON_POSE_DEHLT);
2082 strcat(string,tmpstr);
2088 static char *ipodriver_channelselect_pup(int is_armature)
2090 static char string[1024];
2093 strcpy(string, "Driver channel: %t");
2094 tmp= string+strlen(string);
2096 tmp+= sprintf(tmp, "|Loc X %%x%d", OB_LOC_X);
2097 tmp+= sprintf(tmp, "|Loc Y %%x%d", OB_LOC_Y);
2098 tmp+= sprintf(tmp, "|Loc Z %%x%d", OB_LOC_Z);
2099 tmp+= sprintf(tmp, "|Rot X %%x%d", OB_ROT_X);
2100 tmp+= sprintf(tmp, "|Rot Y %%x%d", OB_ROT_Y);
2101 tmp+= sprintf(tmp, "|Rot Z %%x%d", OB_ROT_Z);
2102 tmp+= sprintf(tmp, "|Scale X %%x%d", OB_SIZE_X);
2103 tmp+= sprintf(tmp, "|Scale Y %%x%d", OB_SIZE_Y);
2104 tmp+= sprintf(tmp, "|Scale Z %%x%d", OB_SIZE_Z);
2106 tmp+= sprintf(tmp, "|Rotation Difference %%x%d", OB_ROT_DIFF);
2111 static void ipo_panel_properties(short cntrl) // IPO_HANDLER_PROPERTIES
2113 extern int totipo_curve; // editipo.c
2118 block= uiNewBlock(&curarea->uiblocks, "ipo_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
2119 uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
2120 uiSetPanelHandler(IPO_HANDLER_PROPERTIES); // for close and esc
2121 if(uiNewPanel(curarea, block, "Transform Properties", "Ipo", 10, 230, 318, 204)==0) return;
2123 /* this is new panel height, newpanel doesnt force new size on existing panels */
2124 uiNewPanelHeight(block, 204);
2126 /* driver buttons first */
2127 ei= get_active_editipo();
2130 sprintf(name, "Driven Channel: %s", ei->name);
2131 uiDefBut(block, LABEL, 0, name, 10, 265, 200, 19, NULL, 1.0, 0.0, 0, 0, "");
2133 if(ei->icu && ei->icu->driver) {
2134 IpoDriver *driver= ei->icu->driver;
2136 uiDefBut(block, BUT, B_IPO_DRIVER, "Remove", 210,265,100,20, NULL, 0.0f, 0.0f, 0, 0, "Remove Driver for this Ipo Channel");
2138 uiBlockBeginAlign(block);
2139 uiDefIconButS(block, TOG, B_IPO_DRIVERTYPE, ICON_PYTHON, 10,240,25,20, &driver->type, (float)IPO_DRIVER_TYPE_NORMAL, (float)IPO_DRIVER_TYPE_PYTHON, 0, 0, "Use a one-line Python Expression as Driver");
2141 if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
2142 uiDefBut(block, TEX, B_IPO_REDR, "", 35,240,275,20, driver->name, 0, 127, 0, 0, "Python Expression");
2143 uiBlockEndAlign(block);
2144 if(driver->flag & IPO_DRIVER_FLAG_INVALID) {
2145 uiDefBut(block, LABEL, 0, "Error: invalid Python expression",
2146 5,215,230,19, NULL, 0, 0, 0, 0, "");
2150 uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_IPO_DEPCHANGE, "OB:", 35, 240, 125, 20, &(driver->ob), "Driver Object");
2152 int icon=ICON_OBJECT;
2154 if(driver->ob->type==OB_ARMATURE && driver->blocktype==ID_AR) {
2155 icon = ICON_POSE_DEHLT;
2156 uiDefBut(block, TEX, B_IPO_REDR, "BO:", 10,220,150,20, driver->name, 0, 31, 0, 0, "Bone name");
2158 if(driver->adrcode==OB_ROT_DIFF)
2159 uiDefBut(block, TEX, B_IPO_REDR, "BO:", 10,200,150,20, driver->name+DRIVER_NAME_OFFS, 0, 31, 0, 0, "Bone name for angular reference");
2162 else driver->blocktype= ID_OB; /* safety when switching object button */
2164 uiBlockBeginAlign(block);
2165 uiDefIconTextButS(block, MENU, B_IPO_DEPCHANGE, icon,
2166 ipodriver_modeselect_pup(driver->ob), 165,240,145,20, &(driver->blocktype), 0, 0, 0, 0, "Driver type");
2168 uiDefButS(block, MENU, B_IPO_REDR,
2169 ipodriver_channelselect_pup(driver->ob->type==OB_ARMATURE && driver->blocktype==ID_AR),
2170 165,220,145,20, &(driver->adrcode), 0, 0, 0, 0, "Driver channel");
2172 uiBlockEndAlign(block);
2176 uiDefBut(block, BUT, B_IPO_DRIVER, "Add Driver", 210,265,100,19, NULL, 0.0f, 0.0f, 0, 0, "Create a Driver for this Ipo Channel");
2180 uiDefBut(block, LABEL, 0, " ", 10, 265, 150, 19, NULL, 1.0, 0.0, 0, 0, "");
2182 boundbox_ipo_curves(G.sipo); // should not be needed... transform/draw calls should update
2184 /* note ranges for buttons below are idiot... we need 2 ranges, one for sliding scale, one for real clip */
2185 if(G.sipo->ipo && G.sipo->ipo->curve.first && totipo_curve) {
2186 extern int totipo_vertsel; // editipo.c
2187 uiDefBut(block, LABEL, 0, "Visible curves", 160, 200, 150, 19, NULL, 1.0, 0.0, 0, 0, "");
2189 uiBlockBeginAlign(block);
2190 uiDefButF(block, NUM, B_MUL_IPO, "Xmin:", 10, 180, 150, 19, &G.sipo->tot.xmin, G.sipo->tot.xmin-1000.0, MAXFRAMEF, 100, 0, "");
2191 uiDefButF(block, NUM, B_MUL_IPO, "Xmax:", 160, 180, 150, 19, &G.sipo->tot.xmax, G.sipo->tot.ymin-1000.0, MAXFRAMEF, 100, 0, "");
2193 uiDefButF(block, NUM, B_MUL_IPO, "Ymin:", 10, 160, 150, 19, &G.sipo->tot.ymin, G.sipo->tot.ymin-1000.0, 5000.0, 100, 0, "");
2194 uiDefButF(block, NUM, B_MUL_IPO, "Ymax:", 160, 160, 150, 19, &G.sipo->tot.ymax, G.sipo->tot.ymin-1000.0, 5000.0, 100, 0, "");
2197 if(totipo_vertsel) {
2198 uiBlockBeginAlign(block);
2199 uiDefButF(block, NUM, B_IPO_NONE, "Speed:", 10,130,150,19, &hspeed, 0.0, 180.0, 1, 0, "");
2200 uiDefBut(block, BUT, B_SETSPEED,"SET", 160,130,50,19, 0, 0, 0, 0, 0, "");
2204 /* this one also does keypositions */
2205 if(G.sipo->ipo) ipo_editvertex_buts(block, G.sipo, -10000, MAXFRAMEF);
2208 static void ipo_blockhandlers(ScrArea *sa)
2210 SpaceIpo *sipo= sa->spacedata.first;
2213 /* warning; blocks need to be freed each time, handlers dont remove (for ipo moved to drawipospace) */
2215 for(a=0; a<SPACE_MAXHANDLER; a+=2) {
2216 switch(sipo->blockhandler[a]) {
2218 case IPO_HANDLER_PROPERTIES:
2219 ipo_panel_properties(sipo->blockhandler[a+1]);
2223 /* clear action value for event */
2224 sipo->blockhandler[a+1]= 0;
2226 uiDrawBlocksPanels(sa, 0);
2231 void drawipospace(ScrArea *sa, void *spacedata)
2233 SpaceIpo *sipo= sa->spacedata.first;
2234 View2D *v2d= &sipo->v2d;
2237 int ofsx, ofsy, a, disptype;
2239 bwin_clear_viewmat(sa->win); /* clear buttons view */
2242 uiFreeBlocksWin(&sa->uiblocks, sa->win); /* for panel handler to work */
2244 test_editipo(0); /* test if current editipo is correct, make_editipo sets v2d->cur, call here because of calc_ipobuttonswidth() */
2246 v2d->hor.xmax+=calc_ipobuttonswidth(sa);
2247 calc_scrollrcts(sa, G.v2d, sa->winx, sa->winy);
2249 BIF_GetThemeColor3fv(TH_BACK, col);
2250 glClearColor(col[0], col[1], col[2], 0.0);
2253 glClearColor(col[0]+0.05,col[1],col[2], 0.0); // litepink
2255 glClearColor(col[0],col[1],col[2], 0.0);
2257 glClear(GL_COLOR_BUFFER_BIT);
2259 if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
2261 ofsx= sa->winrct.xmin; // ivm mywin
2262 ofsy= sa->winrct.ymin;
2263 glViewport(ofsx+v2d->mask.xmin, ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1);
2264 glScissor(ofsx+v2d->mask.xmin, ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1);
2268 myortho2(v2d->cur.xmin, v2d->cur.xmax, v2d->cur.ymin, v2d->cur.ymax);
2272 /* correct scale for degrees? */
2275 for(a=0; a<sipo->totipo; a++, ei++) {
2276 if(ei->flag & IPO_VISIBLE) {
2277 if(disptype== -1) disptype= ei->disptype;
2278 else if(disptype!=ei->disptype) disptype= 0;
2289 //if(sipo->ipokey.first==0) make_ipokey();
2290 //else update_ipokey_val();
2295 if(sipo->blocktype==ID_KE) {
2297 draw_key(sipo, ei->flag & IPO_VISIBLE);
2300 /* map ipo-points for drawing if scaled ipo */
2302 actstrip_map_ipo_keys(OBACT, sipo->ipo, 0, 0);
2307 draw_ipovertices(0);
2312 draw_ipovertices(1);
2314 /* undo mapping of ipo-points for drawing if scaled ipo */
2316 actstrip_map_ipo_keys(OBACT, sipo->ipo, 1, 0);
2318 /* Draw 'curtains' for preview */
2319 draw_anim_preview_timespace();
2322 draw_markers_timespace(SCE_MARKERS, 0);
2324 /* restore viewport */
2327 if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
2329 /* ortho at pixel level sa */
2330 myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
2333 drawscroll(disptype);
2334 draw_solution(sipo);
2345 myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
2346 draw_area_emboss(sa);
2348 /* it is important to end a view in a transform compatible with buttons */
2349 bwin_scalematrix(sa->win, sipo->blockscale, sipo->blockscale, sipo->blockscale);
2350 /* only draw panels when relevant */
2351 if(sipo->editipo) ipo_blockhandlers(sa);
2353 sa->win_swap= WIN_BACK_OK;
2356 void scroll_ipobuts()
2361 tot= 30+IPOBUTY*G.sipo->totipo;
2362 if(tot<curarea->winy) return;
2364 getmouseco_areawin(mval);
2367 while(get_mbut()&M_MOUSE) {
2368 getmouseco_areawin(mval);
2370 G.sipo->butofs+= (mval[1]-yo);
2371 if(G.sipo->butofs<0) G.sipo->butofs= 0;
2372 else if(G.sipo->butofs+curarea->winy>tot) G.sipo->butofs= tot-curarea->winy;
2374 scrarea_do_windraw(curarea);
2375 screen_swapbuffers();
2379 else BIF_wait_for_statechange();
2383 /* total mess function, especially with mousewheel, needs cleanup badly (ton) */
2384 int view2dzoom(unsigned short event)
2387 float fac, dx, dy, wtemp;
2388 short mval[2], mvalo[2];
2389 short is_wheel= (event==WHEELUPMOUSE) || (event==WHEELDOWNMOUSE);
2391 getmouseco_areawin(mvalo);
2395 while( (get_mbut()&(L_MOUSE|M_MOUSE)) || is_wheel ) {
2397 /* regular mousewheel: zoom regular
2398 * alt-shift mousewheel: zoom y only
2399 * alt-ctrl mousewheel: zoom x only
2401 if (event==WHEELUPMOUSE) {
2402 if(U.uiflag & USER_WHEELZOOMDIR)
2406 if(curarea->spacetype!=SPACE_BUTS) wtemp*= 3;
2408 dx= (float)(wtemp*(G.v2d->cur.xmax-G.v2d->cur.xmin));
2409 dy= (float)(wtemp*(G.v2d->cur.ymax-G.v2d->cur.ymin));
2411 switch (G.qual & (LR_CTRLKEY|LR_SHIFTKEY|LR_ALTKEY)) {
2414 case (LR_SHIFTKEY|LR_ALTKEY):
2417 case (LR_CTRLKEY|LR_ALTKEY):
2421 if(curarea->spacetype==SPACE_BUTS); // exception
2426 else if (event==WHEELDOWNMOUSE) {
2427 if(U.uiflag & USER_WHEELZOOMDIR)
2431 if(curarea->spacetype!=SPACE_BUTS) wtemp*= 3;
2433 dx= (float)(wtemp*(G.v2d->cur.xmax-G.v2d->cur.xmin));
2434 dy= (float)(wtemp*(G.v2d->cur.ymax-G.v2d->cur.ymin));
2436 switch (G.qual & (LR_CTRLKEY|LR_SHIFTKEY|LR_ALTKEY)) {
2439 case (LR_SHIFTKEY|LR_ALTKEY):
2442 case (LR_CTRLKEY|LR_ALTKEY):
2446 if(curarea->spacetype==SPACE_BUTS);
2452 getmouseco_areawin(mval);
2453 if(U.viewzoom==USER_ZOOM_SCALE) {
2456 dist = (G.v2d->mask.xmax - G.v2d->mask.xmin)/2.0;
2457 dx= 1.0-(fabs(mvalo[0]-dist)+2.0)/(fabs(mval[0]-dist)+2.0);
2458 dx*= 0.5*(G.v2d->cur.xmax-G.v2d->cur.xmin);
2460 dist = (G.v2d->mask.ymax - G.v2d->mask.ymin)/2.0;
2461 dy= 1.0-(fabs(mvalo[1]-dist)+2.0)/(fabs(mval[1]-dist)+2.0);
2462 dy*= 0.5*(G.v2d->cur.ymax-G.v2d->cur.ymin);
2466 fac= 0.01*(mval[0]-mvalo[0]);
2467 dx= fac*(G.v2d->cur.xmax-G.v2d->cur.xmin);
2468 fac= 0.01*(mval[1]-mvalo[1]);
2469 dy= fac*(G.v2d->cur.ymax-G.v2d->cur.ymin);
2471 if(U.viewzoom==USER_ZOOM_CONT) {
2478 if (ELEM(event, WHEELUPMOUSE, WHEELDOWNMOUSE) || mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
2480 if(U.viewzoom!=USER_ZOOM_CONT) {
2485 if( ELEM(curarea->spacetype, SPACE_NLA, SPACE_ACTION) ) {
2486 if(mvalo[0] < G.v2d->mask.xmin) {
2487 G.v2d->cur.ymin+= dy;
2488 G.v2d->cur.ymax-= dy;
2491 G.v2d->cur.xmin+= dx;
2492 G.v2d->cur.xmax-= dx;
2495 else if (ELEM(curarea->spacetype, SPACE_SOUND, SPACE_TIME)) {
2496 G.v2d->cur.xmin+= dx;
2497 G.v2d->cur.xmax-= dx;
2499 else if (curarea->spacetype == SPACE_SEQ) {
2500 /* less sensitivity on y scale */
2501 G.v2d->cur.xmin+= dx;
2502 G.v2d->cur.xmax-= dx;
2503 if (!(ELEM(event, WHEELUPMOUSE, WHEELDOWNMOUSE))) {
2504 G.v2d->cur.ymin+= dy/2;
2505 G.v2d->cur.ymax-= dy/2;
2509 G.v2d->cur.xmin+= dx;
2510 G.v2d->cur.xmax-= dx;
2511 G.v2d->cur.ymin+= dy;
2512 G.v2d->cur.ymax-= dy;
2515 test_view2d(G.v2d, curarea->winx, curarea->winy); /* cur min max rects */
2517 sa= curarea; /* now when are you going to kill this one! */
2518 view2d_do_locks(curarea, V2D_LOCK_COPY|V2D_LOCK_REDRAW);
2519 areawinset(sa->win);
2521 scrarea_do_windraw(curarea);
2522 screen_swapbuffers();
2524 else BIF_wait_for_statechange();
2525 /* return if we were using the mousewheel
2527 if ( is_wheel ) return 1;
2532 void center_currframe(void)
2534 /* place the current frame in the
2535 * center of the 2D window.
2539 width = G.v2d->cur.xmax - G.v2d->cur.xmin;
2540 G.v2d->cur.xmin = CFRA - 0.5*(width);
2541 G.v2d->cur.xmax = CFRA + 0.5*(width);
2543 test_view2d(G.v2d, curarea->winx, curarea->winy);
2544 view2d_do_locks(curarea, V2D_LOCK_COPY);
2546 scrarea_queue_winredraw(curarea);
2549 /* total mess function, especially with mousewheel, needs cleanup badly (ton) */
2550 int view2dmove(unsigned short event)
2552 /* return 1 when something was done */
2553 float facx=0.0, facy=0.0, dx, dy, left=1.0, right=1.0;
2554 short mval[2], mvalo[2], leftret=1, mousebut;
2555 short is_wheel= (event==WHEELUPMOUSE) || (event==WHEELDOWNMOUSE);
2556 int oldcursor, cursor;
2559 /* when wheel is used, we only draw it once */
2561 /* try to do some zooming if the
2562 * middlemouse and ctrl are pressed
2563 * or if the mousewheel is being used.
2564 * Return if zooming was done.
2567 /* check for left mouse / right mouse button select */
2568 if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
2569 else mousebut = L_MOUSE;
2571 if ( (G.qual & LR_CTRLKEY) || is_wheel ) {
2572 /* patch for oops & buttonswin, standard scroll no zoom */
2573 if(curarea->spacetype==SPACE_OOPS) {
2574 SpaceOops *soops= curarea->spacedata.first;
2575 if(soops->type==SO_OUTLINER);
2576 else if (view2dzoom(event)) {
2580 else if(curarea->spacetype==SPACE_BUTS && (G.qual & LR_CTRLKEY)==0);
2581 else if (view2dzoom(event)) {
2586 /* test where mouse is */
2587 getmouseco_areawin(mvalo);
2588 /* initialize this too */
2592 if ELEM7(curarea->spacetype, SPACE_IPO, SPACE_SEQ, SPACE_OOPS, SPACE_SOUND, SPACE_ACTION, SPACE_NLA, SPACE_TIME) {
2594 if( BLI_in_rcti(&G.v2d->mask, (int)mvalo[0], (int)mvalo[1]) ) {
2595 facx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/(float)(G.v2d->mask.xmax-G.v2d->mask.xmin);
2596 facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
2598 /* stoopid exception to allow scroll in lefthand side */
2599 else if(curarea->spacetype==SPACE_ACTION && BLI_in_rcti(&G.v2d->mask, ACTWIDTH+(int)mvalo[0], (int)mvalo[1]) ) {
2601 facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
2603 else if(curarea->spacetype==SPACE_NLA && BLI_in_rcti(&G.v2d->mask, NLAWIDTH+(int)mvalo[0], (int)mvalo[1]) ) {
2605 facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
2607 else if(IN_2D_VERT_SCROLL((int)mvalo)) {
2608 facy= -(G.v2d->tot.ymax-G.v2d->tot.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
2609 if(get_mbut() & mousebut) {
2610 /* which part of scrollbar should move? */
2611 if(mvalo[1]< (vertymin+vertymax)/2 ) right= 0.0;
2618 else if(IN_2D_HORIZ_SCROLL((int)mvalo)) {
2619 facx= -(G.v2d->tot.xmax-G.v2d->tot.xmin)/(float)(G.v2d->mask.xmax-G.v2d->mask.xmin);
2620 if(get_mbut() & mousebut) {
2621 /* which part of scrollbar should move? */
2622 if(mvalo[0]< (horxmin+horxmax)/2 ) right= 0.0;
2629 facx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/(float)(curarea->winx);
2630 facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(curarea->winy);
2633 cursor = BC_NSEW_SCROLLCURSOR;
2635 /* no y move in audio & time */
2636 if ELEM(curarea->spacetype, SPACE_SOUND, SPACE_TIME) {
2638 cursor = BC_EW_SCROLLCURSOR;
2641 /* store the old cursor to temporarily change it */
2642 oldcursor=get_cursor();
2643 win=winlay_get_active_window();
2646 if(get_mbut() & mousebut && leftret) return 0;
2647 if(facx==0.0 && facy==0.0) return 1;
2649 if (!is_wheel) SetBlenderCursor(cursor);
2651 while( (get_mbut()&(L_MOUSE|M_MOUSE)) || is_wheel) {
2653 /* If the mousewheel is used with shift key
2654 * the scroll up and down. If the mousewheel
2655 * is used with the ctrl key then scroll left
2660 if(event==WHEELDOWNMOUSE) {
2661 facx= -facx; facy= -facy;
2663 switch (G.qual & (LR_CTRLKEY|LR_SHIFTKEY|LR_ALTKEY)) {
2673 if(curarea->spacetype==SPACE_OOPS) {
2677 else if(curarea->spacetype==SPACE_BUTS) {
2678 if(G.buts->align==BUT_HORIZONTAL) {
2679 dx= facx*30; dy= 0.0;
2681 dx= 0.0; dy= facy*30;
2691 getmouseco_areawin(mval);
2692 dx= facx*(mvalo[0]-mval[0]);
2693 dy= facy*(mvalo[1]-mval[1]);
2696 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || is_wheel) {
2699 G.v2d->cur.xmin+= left*dx;
2700 G.v2d->cur.xmax+= right*dx;
2701 G.v2d->cur.ymin+= left*dy;
2702 G.v2d->cur.ymax+= right*dy;
2704 test_view2d(G.v2d, curarea->winx, curarea->winy);
2706 sa= curarea; /* bad global */
2707 view2d_do_locks(curarea, V2D_LOCK_COPY|V2D_LOCK_REDRAW);
2708 areawinset(sa->win);
2710 if(curarea->spacetype==SPACE_OOPS)
2711 ((SpaceOops *)curarea->spacedata.first)->storeflag |= SO_TREESTORE_REDRAW;
2713 scrarea_do_windraw(curarea);
2714 screen_swapbuffers();
2719 else BIF_wait_for_statechange();
2720 /* return if we were using the mousewheel
2722 if ( is_wheel ) return 1;
2725 window_set_cursor(win, oldcursor);
2729 void view2dborder(void)
2734 EditIpo *select_proj_ipo(rctf *rectf, int event)
2737 float xmin, ymin, xmax, ymax;
2738 /* this was IGLuint, but it's a useless typedef... */
2739 GLuint buffer[MAXPICKBUF];
2748 getmouseco_areawin(mval);
2750 mval[0]-= 6; mval[1]-= 6;
2751 areamouseco_to_ipoco(G.v2d, mval, &xmin, &ymin);
2752 mval[0]+= 12; mval[1]+= 12;
2753 areamouseco_to_ipoco(G.v2d, mval, &xmax, &ymax);
2755 myortho2(xmin, xmax, ymin, ymax);
2757 else myortho2(rectf->xmin, rectf->xmax, rectf->ymin, rectf->ymax);
2759 glSelectBuffer( MAXPICKBUF, buffer);
2760 glRenderMode(GL_SELECT);
2761 glInitNames(); /* whatfor? but otherwise it does not work */
2764 /* get rid of buttons view */
2768 init_pickselcode(); /* drawipo.c */
2771 /* restore buttons view */
2776 hits= glRenderMode(GL_RENDER);
2777 glPopName(); /* see above (pushname) */
2778 if(hits<1) return 0;
2781 ei= G.sipo->editipo;
2782 for(a=0; a<G.sipo->totipo; a++, ei++) {
2783 if ISPOIN(ei, icu, flag & IPO_VISIBLE) {
2785 for(b=0; b<hits; b++) {
2786 /* conversion for glSelect */
2787 if(code == buffer[ (4 * b) + 3] ) {
2788 if(event==LEFTMOUSE) ei->flag |= IPO_SELECT;
2789 else ei->flag &= ~IPO_SELECT;
2790 ei->icu->flag= ei->flag;
2795 /* also conversion for glSelect */
2796 if(code==buffer[ 3 ]) return ei;