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