1 /****************************************************************************
2 
3   GLUI User Interface Toolkit
4   ---------------------------
5 
6      glui_scrollbar.cpp - GLUI_Scrollbar class
7 
8           --------------------------------------------------
9 
10   Copyright (c) 2004 John Kew, 1998 Paul Rademacher
11 
12   This software is provided 'as-is', without any express or implied
13   warranty. In no event will the authors be held liable for any damages
14   arising from the use of this software.
15 
16   Permission is granted to anyone to use this software for any purpose,
17   including commercial applications, and to alter it and redistribute it
18   freely, subject to the following restrictions:
19 
20   1. The origin of this software must not be misrepresented; you must not
21   claim that you wrote the original software. If you use this software
22   in a product, an acknowledgment in the product documentation would be
23   appreciated but is not required.
24   2. Altered source versions must be plainly marked as such, and must not be
25   misrepresented as being the original software.
26   3. This notice may not be removed or altered from any source distribution.
27 
28 *****************************************************************************/
29 
30 #include "glui_internal_control.h"
31 #include <cmath>
32 #include <cassert>
33 
34 /*static int __debug=0;              */
35 
36 #define  GLUI_SCROLL_GROWTH_STEPS         800
37 #define  GLUI_SCROLL_MIN_GROWTH_STEPS     100
38 #define  GLUI_SCROLL_CALLBACK_INTERVAL    1    /* Execute the user's callback every this many clicks */
39 
40 enum {
41   GLUI_SCROLL_ARROW_UP,
42   GLUI_SCROLL_ARROW_DOWN,
43   GLUI_SCROLL_ARROW_LEFT,
44   GLUI_SCROLL_ARROW_RIGHT
45 };
46 
47 
48 /****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/
49 // Constructor, no live var
GLUI_Scrollbar(GLUI_Node * parent,const char * name,int horz_vert,int data_type,int id,GLUI_CB callback)50 GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent,
51                                 const char *name,
52                                 int horz_vert,
53                                 int data_type,
54                                 int id, GLUI_CB callback
55                                 /*,GLUI_Control *object
56                                 ,GLUI_InterObject_CB obj_cb*/
57                                 )
58 {
59   common_construct(parent, name, horz_vert, data_type, NULL, id, callback/*, object, obj_cb*/);
60 }
61 
62 /****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/
63 // Constructor, int live var
GLUI_Scrollbar(GLUI_Node * parent,const char * name,int horz_vert,int * live_var,int id,GLUI_CB callback)64 GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, const char *name,
65                                 int horz_vert,
66                                 int *live_var,
67                                 int id, GLUI_CB callback
68                                 /*,GLUI_Control *object
69                                 ,GLUI_InterObject_CB obj_cb*/
70                                 )
71 {
72   common_construct(parent, name, horz_vert, GLUI_SCROLL_INT, live_var, id, callback/*, object, obj_cb*/);
73 }
74 
75 /****************************** GLUI_Scrollbar::GLUI_Scrollbar() **********/
76 // Constructor, float live var
GLUI_Scrollbar(GLUI_Node * parent,const char * name,int horz_vert,float * live_var,int id,GLUI_CB callback)77 GLUI_Scrollbar::GLUI_Scrollbar( GLUI_Node *parent, const char *name,
78                                 int horz_vert,
79                                 float *live_var,
80                                 int id, GLUI_CB callback
81                                 /*,GLUI_Control *object
82                                 ,GLUI_InterObject_CB obj_cb*/
83                                 )
84 {
85   common_construct(parent, name, horz_vert, GLUI_SCROLL_FLOAT, live_var, id, callback/*, object, obj_cb*/);
86 }
87 
88 /****************************** GLUI_Scrollbar::common_init() **********/
common_init(void)89 void GLUI_Scrollbar::common_init(void)
90 {
91    horizontal	= true;
92    h		= GLUI_SCROLL_ARROW_HEIGHT;
93    w		= GLUI_TEXTBOX_WIDTH;
94    alignment	= GLUI_ALIGN_CENTER;
95    x_off	= 0;
96    y_off_top	= 0;
97    y_off_bot	= 0;
98    can_activate = true;
99    state	= GLUI_SCROLL_STATE_NONE;
100    growth_exp	= GLUI_SCROLL_DEFAULT_GROWTH_EXP;
101    callback_count = 0;
102    first_callback = true;
103    user_speed	= 1.0;
104    float_min	= 0.0;
105    float_max	= 0.0;
106    int_min	= 0;
107    int_max	= 0;
108    associated_object = NULL;
109    last_update_time=0;
110    velocity_limit=50.0; /* Change value by at most 50 per second */
111    box_length	      = 0;
112    box_start_position = 0;
113    box_end_position   = 0;
114    track_length       = 0;
115 }
116 
117 /****************************** GLUI_Scrollbar::common_construct() **********/
common_construct(GLUI_Node * parent,const char * name,int horz_vert,int data_type,void * data,int id,GLUI_CB callback)118 void GLUI_Scrollbar::common_construct(
119   GLUI_Node *parent,
120   const char *name,
121   int horz_vert,
122   int data_type,
123   void *data,
124   int id, GLUI_CB callback
125   /*,GLUI_Control *object,
126   GLUI_InterObject_CB obj_cb*/
127   )
128 {
129   common_init();
130 
131   // make sure limits are wide enough to hold live value
132   if (data_type==GLUI_SCROLL_FLOAT) {
133     float lo = 0.0f, hi=1.0f;
134     if (data) {
135       float d = *(float*)(data);
136       lo = MIN(lo, d);
137       hi = MAX(hi, d);
138     }
139     this->set_float_limits(lo,hi);
140     this->set_float_val(lo);
141     this->live_type = GLUI_LIVE_FLOAT;
142   } else {
143     int lo = 0, hi=100;
144     if (data) {
145       int d = *(int*)(data);
146       lo = MIN(lo, d);
147       hi = MAX(hi, d);
148     }
149     this->set_int_limits(lo,hi);
150     this->set_int_val(0);
151     this->live_type = GLUI_LIVE_INT;
152   }
153   this->data_type = data_type;
154   this->set_ptr_val( data );
155   this->set_name(name);
156   this->user_id = id;
157   this->callback    = callback;
158   //this->associated_object = object;
159   //this->object_cb = obj_cb;
160   this->horizontal=(horz_vert==GLUI_SCROLL_HORIZONTAL);
161   if (this->horizontal) {
162     this->h = GLUI_SCROLL_ARROW_HEIGHT;
163     this->w = GLUI_TEXTBOX_WIDTH;
164   } else {
165     this->h = GLUI_TEXTBOX_HEIGHT;
166     this->w = GLUI_SCROLL_ARROW_WIDTH;
167   }
168   parent->add_control( this );
169   this->init_live();
170 }
171 
172 /****************************** GLUI_Scrollbar::mouse_down_handler() **********/
173 
mouse_down_handler(int local_x,int local_y)174 int    GLUI_Scrollbar::mouse_down_handler( int local_x, int local_y )
175 {
176   last_update_time=GLUI_Time()-1.0;
177   this->state = find_arrow( local_x, local_y );
178   GLUI_Master.glui_setIdleFuncIfNecessary();
179 
180   /*  printf( "spinner: mouse down  : %d/%d   arrow:%d\n", local_x, local_y,
181       find_arrow( local_x, local_y ));
182       */
183 
184   if ( state != GLUI_SCROLL_STATE_UP AND state != GLUI_SCROLL_STATE_DOWN)
185     return true;
186 
187   reset_growth();
188 
189   /*** ints and floats behave a bit differently.  When you click on
190     an int spinner, you expect the value to immediately go up by 1, whereas
191     for a float it'll go up only by a fractional amount.  Therefore, we
192     go ahead and increment by one for int spinners ***/
193 #if 1
194   if ( data_type == GLUI_SCROLL_INT ) {
195     // Allow for possibility of reversed limits
196     int lo = MIN(int_min,int_max);
197     int hi = MAX(int_min,int_max);
198     int increase = int_min < int_max ? 1 : -1;
199     int new_val = int_val;
200     if ( state == GLUI_SCROLL_STATE_UP ) {
201       new_val += increase;
202     } else if ( state == GLUI_SCROLL_STATE_DOWN ) {
203       new_val -= increase;
204     }
205     if (new_val >= lo && new_val <= hi && new_val!=int_val) {
206       set_int_val(new_val);
207       do_callbacks();
208     }
209   }
210 #endif
211   do_click();
212   redraw();
213 
214   return false;
215 }
216 
217 
218 /******************************** GLUI_Scrollbar::mouse_up_handler() **********/
219 
mouse_up_handler(int local_x,int local_y,bool inside)220 int    GLUI_Scrollbar::mouse_up_handler( int local_x, int local_y, bool inside )
221 {
222   state = GLUI_SCROLL_STATE_NONE;
223   GLUI_Master.glui_setIdleFuncIfNecessary();
224 
225   /*  printf("spinner: mouse up  : %d/%d    inside: %d\n",local_x,local_y,inside);              */
226 
227   /*glutSetCursor( GLUT_CURSOR_INHERIT );              */
228   glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
229 
230   redraw();
231 
232   /*  do_callbacks(); --- stub               */
233   /*  if ( callback )               */
234   /*  callback( this->user_id );              */
235 
236   return false;
237 }
238 
239 
240 /***************************** GLUI_Scrollbar::mouse_held_down_handler() ******/
241 
mouse_held_down_handler(int local_x,int local_y,bool new_inside)242 int    GLUI_Scrollbar::mouse_held_down_handler( int local_x, int local_y,
243                                                 bool new_inside)
244 {
245   int new_state;
246   if ( state == GLUI_SCROLL_STATE_NONE )
247     return false;
248 
249   /*  printf("spinner: mouse held: %d/%d    inside: %d\n",local_x,local_y,
250       new_inside);
251   */
252 
253   if ( state == GLUI_SCROLL_STATE_SCROLL) {   /* dragging? */
254     do_drag( local_x-x_abs, local_y-y_abs );
255   }
256   else {                                      /* not dragging */
257     new_state = find_arrow( local_x, local_y );
258 
259     if ( new_state == state ) {
260       /** Still in same arrow **/
261       do_click();
262     }
263   }
264   redraw();
265 
266   return false;
267 }
268 
269 
270 /****************************** GLUI_Scrollbar::key_handler() **********/
271 
key_handler(unsigned char key,int modifiers)272 int    GLUI_Scrollbar::key_handler( unsigned char key,int modifiers )
273 {
274   return true;
275 }
276 
277 
278 /****************************** GLUI_Scrollbar::draw() **********/
279 
draw(int x,int y)280 void    GLUI_Scrollbar::draw( int x, int y )
281 {
282   GLUI_DRAWINGSENTINAL_IDIOM
283 
284   if ( horizontal ) {
285     draw_scroll_arrow(GLUI_SCROLL_ARROW_LEFT,  0, 0);
286     draw_scroll_arrow(GLUI_SCROLL_ARROW_RIGHT, w-GLUI_SCROLL_ARROW_WIDTH, 0);
287   } else {
288     draw_scroll_arrow(GLUI_SCROLL_ARROW_UP,  0, 0);
289     draw_scroll_arrow(GLUI_SCROLL_ARROW_DOWN, 0, h-GLUI_SCROLL_ARROW_HEIGHT);
290   }
291   draw_scroll();
292 }
293 
294 
295 /****************************** GLUI_Scrollbar::draw_scroll_arrow() **********/
296 
draw_scroll_arrow(int arrowtype,int x,int y)297 void GLUI_Scrollbar::draw_scroll_arrow(int arrowtype, int x, int y)
298 {
299   float offset=0;
300   float L=3.5f,HC=7.f,R=10.5f;
301   float T=4.5f,VC=8.f,B=11.5;
302   const float verts[][6]={
303     { L,10.5f,     R, 10.5f,      HC, 6.5f }, // up arrow
304     { L,6.5f,      R, 6.5f,       HC,10.5f }, // down arrow
305     { R-2,T,       R-2, B,        L+1,  VC   }, // left arrow
306     { L+2,T,       L+2, B,        R-1,  VC   }  // right arrow
307   };
308 
309   const float *tri = NULL;
310 
311   switch (arrowtype)
312   {
313     case GLUI_SCROLL_ARROW_UP:
314       tri = verts[0];
315       if (state & GLUI_SCROLL_STATE_UP) offset = 1;
316       break;
317 
318     case GLUI_SCROLL_ARROW_DOWN:
319       tri = verts[1];
320       if (state & GLUI_SCROLL_STATE_DOWN) offset = 1;
321       break;
322 
323     case GLUI_SCROLL_ARROW_LEFT:
324       tri = verts[2];
325       if (state & GLUI_SCROLL_STATE_DOWN) offset = 1;
326       break;
327 
328     case GLUI_SCROLL_ARROW_RIGHT:
329       tri = verts[3];
330       if (state & GLUI_SCROLL_STATE_UP) offset = 1;
331       break;
332 
333     default:
334       return; /* tri is NULL */
335   }
336 
337   glColor3ubv(glui->bkgd_color);
338   glRecti(x,y,x+GLUI_SCROLL_ARROW_WIDTH,y+GLUI_SCROLL_ARROW_HEIGHT);
339   if (!offset) {
340     glui->draw_raised_box(x,y+1,GLUI_SCROLL_ARROW_WIDTH-1,GLUI_SCROLL_ARROW_HEIGHT-1);
341   } else {
342     glColor3ub(128,128,128);
343     glBegin(GL_LINE_LOOP);
344     int x2=x+GLUI_SCROLL_ARROW_WIDTH, y2=y+GLUI_SCROLL_ARROW_HEIGHT;
345     glVertex2i(x ,y);
346     glVertex2i(x2,y);
347     glVertex2i(x2,y2);
348     glVertex2i(x ,y2);
349     glEnd();
350   }
351 
352   GLubyte black[]={0,0,0};
353   GLubyte white[]={255,255,255};
354   GLubyte  gray[]={128,128,128};
355   GLubyte *color=black;
356   if (!enabled) {
357     offset = 1;
358     color = white;
359   }
360   glTranslatef(x+offset,y+offset,0);
361   glColor3ubv(color);
362   glBegin(GL_TRIANGLES);
363   glVertex2fv(tri); glVertex2fv(tri+2), glVertex2fv(tri+4);
364   glEnd();
365   glTranslatef(-(x+offset),-(y+offset),0);
366 
367   if (!enabled) { // once more!
368     glTranslatef(x,y,0);
369     glColor3ubv(gray);
370     glBegin(GL_TRIANGLES);
371     glVertex2fv(tri); glVertex2fv(tri+2), glVertex2fv(tri+4);
372     glEnd();
373     glTranslatef(-x,-y,0);
374   }
375 }
376 
377 
draw_scroll()378 void GLUI_Scrollbar::draw_scroll() {
379   update_scroll_parameters();
380 
381   // Draw track using a checkerboard background
382   const unsigned char scroll_bg[] = {
383     0xD4, 0xD0, 0xC8, 0xFF, 0xFF, 0xFF,
384     0xFF, 0xFF, 0xFF, 0xD4, 0xD0, 0xC8
385   };
386   glColor3f( 1.0, 1.0, 1.0 );
387   glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
388   glEnable( GL_TEXTURE_2D);
389   glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
390   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
391   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
392   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
393   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
394   glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE,
395   	  scroll_bg);
396 
397   float y0 = horizontal? 0 : GLUI_SCROLL_ARROW_HEIGHT;
398   float y1 = horizontal? h : h-GLUI_SCROLL_ARROW_HEIGHT;
399   float x0 = horizontal? GLUI_SCROLL_ARROW_WIDTH   : 0;
400   float x1 = horizontal? w-GLUI_SCROLL_ARROW_WIDTH : w;
401   x0-=0.5; y0+=0.5;
402   x1-=0.5; y1+=0.5;
403   float dy = y1-y0;
404   float dx = x1-x0;
405   glBegin(GL_QUADS);
406   glTexCoord2f(0,     0);        glVertex2f(x0,y0);
407   glTexCoord2f(dx*0.5f,0);       glVertex2f(x1,y0);
408   glTexCoord2f(dx*0.5f,dy*0.5f); glVertex2f(x1,y1);
409   glTexCoord2f(0,      dy*0.5f); glVertex2f(x0,y1);
410   glEnd();
411   glDisable(GL_TEXTURE_2D);
412 
413   // Draw scroll box
414   int box = box_start_position;
415   if (horizontal) {
416     box += GLUI_SCROLL_ARROW_WIDTH;
417     draw_scroll_box(box,1,box_length,h);
418   } else {
419     box += GLUI_SCROLL_ARROW_HEIGHT+1;
420     draw_scroll_box(0,box,w,box_length);
421   }
422 }
423 
424 /****************************** GLUI_Scrollbar::draw_scroll_box() **********/
425 
draw_scroll_box(int x,int y,int w,int h)426 void GLUI_Scrollbar::draw_scroll_box(int x, int y, int w, int h)
427 {
428   if (!enabled) return;
429   glColor3ubv(glui->bkgd_color);
430   glRecti(x,y,x+w,y+h);
431   glui->draw_raised_box(x,y, w-1, h-1);
432 
433   if (active) {
434     glEnable( GL_LINE_STIPPLE );
435     glLineStipple( 1, 0x5555 );
436     glColor3f( 0., 0., 0. );
437     glBegin(GL_LINE_LOOP);
438     int x1 = x+2, y1 = y+2, x2 = x+w-4, y2 = y+h-4;
439     glVertex2i(x1,y1);
440     glVertex2i(x2,y1);
441     glVertex2i(x2,y2);
442     glVertex2i(x1,y2);
443     glEnd();
444     glDisable( GL_LINE_STIPPLE );
445   }
446 }
447 
448 
449 
450 /**************************** update_scroll_parameters ***********/
451 
update_scroll_parameters()452 void GLUI_Scrollbar::update_scroll_parameters() {
453   track_length = horizontal?
454     this->w-GLUI_SCROLL_ARROW_WIDTH*2 :
455     this->h-GLUI_SCROLL_ARROW_HEIGHT*2;
456   if (data_type==GLUI_SCROLL_INT)
457   {
458     if (int_max==int_min)
459       box_length=track_length;
460     else {
461       const int MIN_TAB = GLUI_SCROLL_BOX_STD_HEIGHT;
462       //box_length = int(track_length/float(visible_range));
463       //if (box_length < MIN_TAB)
464         box_length = MIN_TAB;
465     }
466     float pixels_per_unit = (track_length-box_length)/float(int_max-int_min);
467     if (horizontal)
468       box_start_position = int((int_val-int_min)*pixels_per_unit);
469     else
470       box_start_position = int((int_max-int_val)*pixels_per_unit);
471     box_end_position = box_start_position+box_length;
472   }
473   else if (data_type==GLUI_SCROLL_FLOAT)
474   {
475     if (float_max==float_min)
476       box_length=track_length;
477     else {
478       box_length = GLUI_SCROLL_BOX_STD_HEIGHT;
479     }
480     float pixels_per_unit = (track_length-box_length)/float(float_max-float_min);
481     if (horizontal)
482       box_start_position = int((float_val-float_min)*pixels_per_unit);
483     else
484       box_start_position = int((float_max-float_val)*pixels_per_unit);
485     box_end_position = box_start_position+box_length;
486   }
487 }
488 
489 
490 /********************************* GLUI_Scrollbar::special_handler() **********/
491 
special_handler(int key,int modifiers)492 int    GLUI_Scrollbar::special_handler( int key,int modifiers )
493 {
494   if ( !horizontal && key == GLUT_KEY_UP ) {
495     mouse_down_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
496       y_abs + 1 );
497     mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
498       y_abs + 1, true );
499   }
500   else if ( !horizontal && key == GLUT_KEY_DOWN ) {
501     mouse_down_handler(x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
502       y_abs+1+GLUI_SCROLL_ARROW_HEIGHT);
503     mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
504       y_abs+1 +GLUI_SCROLL_ARROW_HEIGHT,
505       true );
506   }
507   if ( horizontal && key == GLUT_KEY_LEFT ) {
508     mouse_down_handler( x_abs + 1,y_abs + 1 );
509     mouse_up_handler( x_abs + 1,   y_abs + 1, true );
510   }
511   else if ( horizontal && key == GLUT_KEY_RIGHT ) {
512     mouse_down_handler(x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
513       y_abs+1);
514     mouse_up_handler( x_abs + w - GLUI_SCROLL_ARROW_WIDTH + 1,
515       y_abs+1,
516       true );
517   }
518   else if ( key == GLUT_KEY_HOME ) {  /** Set value to limit top -
519                                           or increment by 10 **/
520   }
521   else if ( key == GLUT_KEY_END ) {
522   }
523 
524   return true;
525 }
526 
527 
528 /************************************ GLUI_Scrollbar::update_size() **********/
529 
update_size(void)530 void   GLUI_Scrollbar::update_size( void )
531 {
532   if (horizontal) {
533     h = GLUI_SCROLL_ARROW_HEIGHT;
534     if (associated_object) {
535       this->w = ((GLUI_Control *)associated_object)->w;
536     }
537   }
538   else {
539     w = GLUI_SCROLL_ARROW_WIDTH;
540     if (associated_object) {
541       this->h = ((GLUI_Control *)associated_object)->h;
542     }
543   }
544 }
545 
546 
547 /************************************ GLUI_Scrollbar::find_arrow() ************/
548 
find_arrow(int local_x,int local_y)549 int    GLUI_Scrollbar::find_arrow( int local_x, int local_y )
550 {
551 
552   local_x = local_x-x_abs;
553   local_y = local_y-y_abs;
554 
555   if (horizontal)
556   {
557     if ( local_y >=  h-GLUI_SCROLL_ARROW_HEIGHT-3 && local_y <= h)
558     {
559       update_scroll_parameters();
560       if ( local_x >= 0 AND local_x <= (GLUI_SCROLL_ARROW_WIDTH+box_start_position) )
561       {
562         return GLUI_SCROLL_STATE_DOWN;
563       }
564       if ( local_x >= (GLUI_SCROLL_ARROW_WIDTH+box_end_position)
565            AND local_x <= (w+GLUI_SCROLL_ARROW_WIDTH) )
566       {
567         return GLUI_SCROLL_STATE_UP;
568       }
569       return GLUI_SCROLL_STATE_SCROLL;
570     }
571   }
572   else
573   {
574     if ( local_x >=  w-GLUI_SCROLL_ARROW_WIDTH-3 && local_x <= w)
575     {
576       update_scroll_parameters();
577       if ( local_y >= 0 AND local_y <= (GLUI_SCROLL_ARROW_HEIGHT+box_start_position) )
578       {
579         return GLUI_SCROLL_STATE_UP;
580       }
581       if ( local_y >= (GLUI_SCROLL_ARROW_HEIGHT+box_end_position)
582            AND local_y <= (h+GLUI_SCROLL_ARROW_HEIGHT) )
583       {
584         return GLUI_SCROLL_STATE_DOWN;
585       }
586       return GLUI_SCROLL_STATE_SCROLL;
587     }
588   }
589 
590   return GLUI_SCROLL_STATE_NONE;
591 }
592 
593 /***************************************** GLUI_Scrollbar::do_click() **********/
594 
do_click(void)595 void    GLUI_Scrollbar::do_click( void )
596 {
597   int    direction = 0;
598 
599   if ( state == GLUI_SCROLL_STATE_UP )
600     direction = +1;
601   else if ( state == GLUI_SCROLL_STATE_DOWN )
602     direction = -1;
603 
604   if (data_type==GLUI_SCROLL_INT&&int_min>int_max) direction*=-1;
605   if (data_type==GLUI_SCROLL_FLOAT&&float_min>float_max) direction*=-1;
606 
607   increase_growth();
608 
609   float modifier_factor = 1.0;
610   float incr = growth * modifier_factor * user_speed ;
611 
612   double frame_time=GLUI_Time()-last_update_time;
613   double frame_limit=velocity_limit*frame_time;
614   if (incr>frame_limit) incr=frame_limit; /* don't scroll faster than limit */
615   last_update_time=GLUI_Time();
616 
617   float new_val = float_val;
618 
619   new_val += direction * incr;
620   if (1 || data_type==GLUI_SCROLL_FLOAT) set_float_val(new_val);
621   if (0 && data_type==GLUI_SCROLL_INT) set_int_val((int)new_val);
622   //printf("do_click: incr %f  val=%f  float_val=%f\n",incr,new_val,float_val);
623 
624   /*** Now update live variable and do callback.  We don't want
625     to do the callback on each iteration of this function, just on every
626     i^th iteration, where i is given by GLUI_SCROLL_CALLBACK_INTERVAL ****/
627   callback_count++;
628   if ( (callback_count % GLUI_SCROLL_CALLBACK_INTERVAL ) == 0 )
629     do_callbacks();
630 
631 }
632 
633 
634 /***************************************** GLUI_Scrollbar::do_drag() **********/
635 
do_drag(int x,int y)636 void    GLUI_Scrollbar::do_drag( int x, int y )
637 {
638   int   direction = 0;
639   float incr, modifier_factor;
640   /* int delta_x;              */
641   int new_int_val = int_val;
642   float new_float_val = float_val;
643 
644   int free_len = track_length-box_length;
645   if (free_len == 0) return;
646 
647   modifier_factor = 1.0;
648   if ( state == GLUI_SCROLL_STATE_SCROLL) {
649     update_scroll_parameters();
650 
651     int hbox = box_length/2;
652     if (horizontal) {
653       int track_v = x-GLUI_SCROLL_ARROW_WIDTH;
654       new_int_val = int_min + (track_v-hbox)*(int_max-int_min)/free_len;
655       new_float_val = float_min + (track_v-hbox)*(float_max-float_min)/float(free_len);
656     } else {
657       int track_v = y-GLUI_SCROLL_ARROW_HEIGHT;
658       new_int_val = int_max - (track_v-hbox)*(int_max-int_min)/free_len;
659       new_float_val = float_max - (track_v-hbox)*(float_max-float_min)/float(free_len);
660     }
661   }
662   else {
663     if ( state == GLUI_SCROLL_STATE_UP )
664       direction = +1;
665     else if ( state == GLUI_SCROLL_STATE_DOWN )
666       direction = -1;
667     incr = growth * direction * modifier_factor * user_speed;
668     new_int_val += direction;
669     new_float_val += direction * (float_max-float_min)/free_len;
670   }
671   last_y = y;
672   last_x = x;
673 
674   /*** Now update live variable and do callback.  We don't want
675     to do the callback on each iteration of this function, just on every
676     i^th iteration, where i is given by GLUI_SCROLL_CALLBACK_INTERVAL ****/
677   if(data_type==GLUI_SCROLL_INT)
678     set_int_val(new_int_val);
679   else if (data_type==GLUI_SCROLL_FLOAT)
680     set_float_val(new_float_val);
681 
682   callback_count++;
683   if ( (callback_count % GLUI_SCROLL_CALLBACK_INTERVAL ) == 0 )
684     do_callbacks();
685 }
686 
687 
688 /***************************************** GLUI_Scrollbar::needs_idle() ******/
689 
needs_idle(void) const690 bool GLUI_Scrollbar::needs_idle( void ) const
691 {
692   if  (state == GLUI_SCROLL_STATE_UP OR state == GLUI_SCROLL_STATE_DOWN ) {
693     return true;
694   }
695   else {
696     return false;
697   }
698 }
699 
700 /***************************************** GLUI_Scrollbar::idle() **********/
701 
idle(void)702 void    GLUI_Scrollbar::idle( void )
703 {
704   if ( NOT needs_idle() )
705     return;
706   else
707     do_click();
708 }
709 
710 
711 /************************************ GLUI_Scrollbar::do_callbacks() **********/
712 
do_callbacks(void)713 void    GLUI_Scrollbar::do_callbacks( void )
714 {
715 
716   /*    *******************************************/
717 
718   if ( NOT first_callback ) {
719     if ( data_type == GLUI_SCROLL_INT AND int_val == last_int_val ) {
720       return;
721     }
722     if ( data_type == GLUI_SPINNER_FLOAT AND float_val == last_float_val ) {
723       return;
724     }
725   }
726 
727   if (associated_object == NULL) {
728     this->execute_callback();
729   }
730   else  {                      // Use internal Callbacks
731     if (object_cb) {
732       //object_cb(associated_object, int_val);
733       object_cb(this);
734     }
735   }
736   last_int_val   = int_val;
737   last_float_val = float_val;
738   first_callback = false;
739 }
740 
741 
742 /********************************** GLUI_Scrollbar::set_float_val() ************/
743 
set_float_val(float new_val)744 void   GLUI_Scrollbar::set_float_val( float new_val )
745 {
746   // Allow for the possibility that the limits are reversed
747   float hi = MAX(float_min,float_max);
748   float lo = MIN(float_min,float_max);
749   if (new_val > hi)
750     new_val = hi;
751   if (new_val < lo)
752     new_val = lo;
753   last_float_val = float_val;
754   float_val = new_val;
755   int_val = (int)new_val;
756 
757   redraw();
758 
759   /*** Now update the live variable ***/
760   output_live(true);
761 }
762 
763 
764 /********************************** GLUI_Scrollbar::set_int_val() ************/
765 
set_int_val(int new_val)766 void   GLUI_Scrollbar::set_int_val( int new_val )
767 {
768   // Allow for the possibility that the limits are reversed
769   int hi = MAX(int_min,int_max);
770   int lo = MIN(int_min,int_max);
771   if (new_val > hi)
772     new_val = hi;
773   if (new_val < lo)
774     new_val = lo;
775   last_int_val = int_val;
776   float_val = int_val = new_val;
777 
778   redraw();
779 
780   /*** Now update the live variable ***/
781   output_live(true);
782 }
783 
784 /*********************************** GLUI_Scrollbar::set_float_limits() *********/
785 
set_float_limits(float low,float high,int limit_type)786 void   GLUI_Scrollbar::set_float_limits( float low, float high, int limit_type )
787 {
788   if (limit_type != GLUI_LIMIT_CLAMP) {
789     // error!
790   }
791   float_min = low;
792   float_max = high;
793   // Allow for possiblitly of reversed limits
794   float lo = MIN(low,high);
795   float hi = MAX(low,high);
796   if (float_val<lo) set_float_val(lo);
797   if (float_val>hi) set_float_val(hi);
798 }
799 
800 
801 /*********************************** GLUI_Scrollbar::set_int_limits() *********/
802 
set_int_limits(int low,int high,int limit_type)803 void   GLUI_Scrollbar::set_int_limits( int low, int high, int limit_type )
804 {
805   if (limit_type != GLUI_LIMIT_CLAMP) {
806     // error!
807   }
808   int_min = low;
809   int_max = high;
810   // Allow for possiblitly of reversed limits
811   int lo = MIN(low,high);
812   int hi = MAX(low,high);
813   if (int_val<lo) set_int_val(lo);
814   if (int_val>hi) set_int_val(hi);
815   float_min = low;
816   float_max = high;
817 }
818 
819 
820 /*********************************** GLUI_Scrollbar::reset_growth() *************/
821 
reset_growth(void)822 void    GLUI_Scrollbar::reset_growth( void )
823 {
824   growth = fabs(float_max - float_min) / float(GLUI_SCROLL_GROWTH_STEPS);
825   if (data_type == GLUI_SCROLL_INT && growth<1) growth=1;
826 }
827 
828 
829 /******************************* GLUI_Scrollbar::increase_growth() *************/
830 
increase_growth(void)831 void    GLUI_Scrollbar::increase_growth( void )
832 {
833   float range=0;
834   if (data_type==GLUI_SCROLL_FLOAT)
835     range = fabs(float_max-float_min);
836   else
837     range = fabs(float(int_max-int_min));
838   if ( growth < (range / float(GLUI_SCROLL_MIN_GROWTH_STEPS)) )
839     growth *= growth_exp;
840   return;
841 }
842 
843 
844 
845