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