1
/****************************************************************************
3
GLUI User Interface Toolkit
4
---------------------------
6
glui_spinner.cpp - GLUI_Spinner class
10
spinner does not explicitly keep track of the current value - this is all
11
handled by the underlying edittext control
12
-> thus, spinner->sync_live() has no meaning, nor spinner->output_live
13
-> BUT, edittext will alter this spinner's float_val and int_val,
14
so that spinner->get/set will work
17
FIXME: there's a heck of a lot of duplication between this and glui_scrollbar.cpp.
21
--------------------------------------------------
23
Copyright (c) 1998 Paul Rademacher
25
WWW: http://sourceforge.net/projects/glui/
26
Forums: http://sourceforge.net/forum/?group_id=92496
28
This library is free software; you can redistribute it and/or
29
modify it under the terms of the GNU Lesser General Public
30
License as published by the Free Software Foundation; either
31
version 2.1 of the License, or (at your option) any later version.
33
This library is distributed in the hope that it will be useful,
34
but WITHOUT ANY WARRANTY; without even the implied warranty of
35
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36
Lesser General Public License for more details.
38
You should have received a copy of the GNU Lesser General Public
39
License along with this library; if not, write to the Free Software
40
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42
*****************************************************************************/
44
#include "glui_internal_control.h"
48
/*static int __debug=0; */
50
#define GLUI_SPINNER_GROWTH_STEPS 800
51
#define GLUI_SPINNER_MIN_GROWTH_STEPS 100
52
#define GLUI_SPINNER_CALLBACK_INTERVAL 1
57
/****************************** GLUI_Spinner::GLUI_Spinner() ****************/
59
GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name,
60
int data_type, int id, GLUI_CB callback )
62
common_construct(parent, name, data_type, NULL, id, callback);
65
/****************************** GLUI_Spinner::GLUI_Spinner() ****************/
67
GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name,
68
int *live_var, int id, GLUI_CB callback )
70
common_construct(parent, name, GLUI_SPINNER_INT, live_var, id, callback);
73
/****************************** GLUI_Spinner::GLUI_Spinner() ****************/
75
GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name,
76
float *live_var, int id, GLUI_CB callback )
78
common_construct(parent, name, GLUI_SPINNER_FLOAT, live_var, id, callback);
81
/****************************** GLUI_Spinner::GLUI_Spinner() ****************/
83
GLUI_Spinner::GLUI_Spinner( GLUI_Node *parent, const char *name,
84
int data_t, void *live_var,
85
int id, GLUI_CB callback )
87
common_construct(parent, name, data_t, live_var, id, callback);
90
/****************************** GLUI_Spinner::common_construct() ************/
92
void GLUI_Spinner::common_construct( GLUI_Node* parent, const char *name,
93
int data_t, void *data,
98
if ( NOT strcmp( name, "Spinner Test" ))
102
if ( data_t == GLUI_SPINNER_INT ) {
103
text_type = GLUI_EDITTEXT_INT;
105
else if ( data_t == GLUI_SPINNER_FLOAT ) {
106
text_type = GLUI_EDITTEXT_FLOAT;
109
assert(0); /* Did not pass in a valid data type */
116
//glui = parent->get_glui();
118
parent->add_control( this );
121
new GLUI_EditText( this, name, text_type, data, id, cb);
123
edittext = txt; /* Link the edittext to the spinner */
124
/* control->ptr_val = data; */
126
edittext->spinner = this; /* Link the spinner to the edittext */
130
/****************************** GLUI_Spinner::mouse_down_handler() **********/
132
int GLUI_Spinner::mouse_down_handler( int local_x, int local_y )
134
this->state = find_arrow( local_x, local_y );
135
GLUI_Master.glui_setIdleFuncIfNecessary();
137
/* printf( "spinner: mouse down : %d/%d arrow:%d\n", local_x, local_y,
138
find_arrow( local_x, local_y ));
141
if ( state != GLUI_SPINNER_STATE_UP AND state != GLUI_SPINNER_STATE_DOWN )
147
/*** ints and floats behave a bit differently. When you click on
148
an int spinner, you expect the value to immediately go up by 1, whereas
149
for a float it'll go up only by a fractional amount. Therefore, we
150
go ahead and increment by one for int spinners ***/
151
if ( data_type == GLUI_SPINNER_INT ) {
152
if ( state == GLUI_SPINNER_STATE_UP )
153
edittext->set_float_val( edittext->float_val + 1.0 );
154
else if ( state == GLUI_SPINNER_STATE_DOWN )
155
edittext->set_float_val( edittext->float_val - .9 );
164
/******************************** GLUI_Spinner::mouse_up_handler() **********/
166
int GLUI_Spinner::mouse_up_handler( int local_x, int local_y, bool inside )
168
state = GLUI_SPINNER_STATE_NONE;
169
GLUI_Master.glui_setIdleFuncIfNecessary();
171
/* printf("spinner: mouse up : %d/%d inside: %d\n",local_x,local_y,inside); */
173
/*glutSetCursor( GLUT_CURSOR_INHERIT ); */
174
glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
177
/* do_callbacks(); --- stub */
178
/* if ( callback ) */
179
/* callback( this->user_id ); */
185
/***************************** GLUI_Spinner::mouse_held_down_handler() ******/
187
int GLUI_Spinner::mouse_held_down_handler( int local_x, int local_y,
192
if ( state == GLUI_SPINNER_STATE_NONE )
195
/* printf("spinner: mouse held: %d/%d inside: %d\n",local_x,local_y,
199
if ( state == GLUI_SPINNER_STATE_BOTH ) { /* dragging? */
200
do_drag( local_x, local_y );
202
else { /* not dragging */
203
new_state = find_arrow( local_x, local_y );
205
if ( new_state == state ) {
206
/** Still in same arrow **/
210
if ( new_inside OR 1) {
211
/** The state changed, but we're still inside - that
212
means we moved off the arrow: begin dragging **/
213
state = GLUI_SPINNER_STATE_BOTH;
216
/*** Here check y of mouse position to determine whether to
223
/*** We switched to up/down dragging ***/
224
if ( state == GLUI_SPINNER_STATE_BOTH ) {
225
glutSetCursor( GLUT_CURSOR_UP_DOWN );
229
/** If the spinner has limits, we reset the growth value, since
230
reset_growth() will compute a new growth value for dragging
231
vs. clicking. If the spinner has no limits, then we just let the
232
growth remain at whatever the user has incremented it up to **/
233
if ( edittext->has_limits != GLUI_LIMIT_NONE )
244
/****************************** GLUI_Spinner::key_handler() **********/
246
int GLUI_Spinner::key_handler( unsigned char key,int modifiers )
254
/****************************** GLUI_Spinner::draw() **********/
256
void GLUI_Spinner::draw( int x, int y )
258
GLUI_DRAWINGSENTINAL_IDIOM
261
/*** Draw the up arrow either pressed or unrpessed ***/
262
if ( state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_BOTH )
263
glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_ON,
264
w-GLUI_SPINNER_ARROW_WIDTH-1,
265
GLUI_SPINNER_ARROW_Y);
267
glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_OFF,
268
w-GLUI_SPINNER_ARROW_WIDTH-1,
269
GLUI_SPINNER_ARROW_Y);
271
/*** Draw the down arrow either pressed or unrpessed ***/
272
if (state == GLUI_SPINNER_STATE_DOWN OR state == GLUI_SPINNER_STATE_BOTH)
273
glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_ON,
274
w-GLUI_SPINNER_ARROW_WIDTH-1,
275
GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y);
277
glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_OFF,
278
w-GLUI_SPINNER_ARROW_WIDTH-1,
279
GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y);
281
else { /**** The spinner is disabled ****/
282
glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_DIS,
283
w-GLUI_SPINNER_ARROW_WIDTH-1,
284
GLUI_SPINNER_ARROW_Y);
285
glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_DIS,
286
w-GLUI_SPINNER_ARROW_WIDTH-1,
287
GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y);
291
glColor3ub( 0, 0, 0 );
292
glEnable( GL_LINE_STIPPLE );
293
glLineStipple( 1, 0x5555 );
296
glColor3ub( glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b );
299
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
300
glDisable( GL_CULL_FACE );
302
glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, 0 );
305
glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, h );
307
glDisable( GL_LINE_STIPPLE );
308
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
312
/********************************* GLUI_Spinner::special_handler() **********/
314
int GLUI_Spinner::special_handler( int key,int modifiers )
316
if ( key == GLUT_KEY_UP ) { /** Simulate a click in the up arrow **/
317
mouse_down_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
318
y_abs + GLUI_SPINNER_ARROW_Y+1 );
319
mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
320
y_abs + GLUI_SPINNER_ARROW_Y+1, true );
322
else if ( key == GLUT_KEY_DOWN ) { /** Simulate a click in the up arrow **/
323
mouse_down_handler(x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
324
y_abs+GLUI_SPINNER_ARROW_Y+1+GLUI_SPINNER_ARROW_HEIGHT);
325
mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
326
y_abs+GLUI_SPINNER_ARROW_Y+1 +GLUI_SPINNER_ARROW_HEIGHT,
329
else if ( key == GLUT_KEY_HOME ) { /** Set value to limit top -
330
or increment by 10 **/
332
else if ( key == GLUT_KEY_END ) {
339
/******************************* GLUI_Spinner::set_float_val() ************/
341
void GLUI_Spinner::set_float_val( float new_val )
346
edittext->set_float_val( new_val );
350
/********************************** GLUI_Spinner::set_int_val() ************/
352
void GLUI_Spinner::set_int_val( int new_val )
357
edittext->set_int_val( new_val );
361
/************************************ GLUI_Spinner::update_size() **********/
363
void GLUI_Spinner::update_size( void )
365
if (!edittext) return;
366
/*edittext->w = this->w - GLUI_SPINNER_ARROW_WIDTH-3; */
367
this->w = edittext->w + GLUI_SPINNER_ARROW_WIDTH + 3;
371
/************************************ GLUI_Spinner::find_arrow() ************/
373
int GLUI_Spinner::find_arrow( int local_x, int local_y )
378
if ( local_x >= (w - GLUI_SPINNER_ARROW_WIDTH) AND
381
if ( local_y >= GLUI_SPINNER_ARROW_Y AND
382
local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT) )
383
return GLUI_SPINNER_STATE_UP;
385
if ( local_y >= GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT AND
386
local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT*2) )
387
return GLUI_SPINNER_STATE_DOWN;
391
return GLUI_SPINNER_STATE_NONE;
395
/***************************************** GLUI_Spinner::do_click() **********/
397
void GLUI_Spinner::do_click( void )
401
float modifier_factor;
403
if ( state == GLUI_SPINNER_STATE_UP )
405
else if ( state == GLUI_SPINNER_STATE_DOWN )
410
modifier_factor = 1.0;
412
if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT )
413
modifier_factor = 100.0f;
414
else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL )
415
modifier_factor = .01f;
418
if ( this->data_type == GLUI_SPINNER_FLOAT OR 1) {
419
incr = growth * direction * modifier_factor * user_speed;
420
edittext->set_float_val( edittext->float_val + incr );
421
/** Remember, edittext mirrors the float and int values ***/
424
/*** Now update live variable and do callback. We don't want
425
to do the callback on each iteration of this function, just on every
426
i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/
428
if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 )
433
/***************************************** GLUI_Spinner::do_drag() **********/
435
void GLUI_Spinner::do_drag( int x, int y )
438
float incr, modifier_factor;
441
modifier_factor = 1.0f;
443
if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT )
444
modifier_factor = 100.0f;
445
else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL )
446
modifier_factor = .01f;
449
/* delta_x = x - last_x; */
450
delta_y = -(y - last_y);
452
if ( this->data_type == GLUI_SPINNER_FLOAT OR 1 ) {
453
incr = growth * delta_y * modifier_factor * user_speed;
454
edittext->set_float_val( edittext->float_val + incr );
455
/** Remember, edittext mirrors the float and int values ***/
461
/*** Now update live variable and do callback. We don't want
462
to do the callback on each iteration of this function, just on every
463
i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/
466
if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 )
471
/***************************************** GLUI_Spinner::needs_idle() ******/
473
bool GLUI_Spinner::needs_idle( void ) const
475
if (state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_DOWN ) {
483
/***************************************** GLUI_Spinner::idle() **********/
485
void GLUI_Spinner::idle( void )
487
if ( NOT needs_idle() )
494
/************************************ GLUI_Spinner::do_callbacks() **********/
496
void GLUI_Spinner::do_callbacks( void )
498
/*** This is not necessary, b/c edittext automatically updates us ***/
501
this->float_val = edittext->float_val;
502
this->int_val = edittext->int_val;
503
/* *******************************************/
505
if ( NOT first_callback ) {
506
if ( data_type == GLUI_SPINNER_INT AND int_val == last_int_val ) {
510
if ( data_type == GLUI_SPINNER_FLOAT AND float_val == last_float_val ) {
515
this->execute_callback();
517
last_int_val = int_val;
518
last_float_val = float_val;
519
first_callback = false;
523
/********************************* GLUI_Spinner::set_float_limits() *********/
525
void GLUI_Spinner::set_float_limits( float low, float high, int limit_type )
530
edittext->set_float_limits( low, high, limit_type );
534
/*********************************** GLUI_Spinner::set_int_limits() *********/
536
void GLUI_Spinner::set_int_limits( int low, int high, int limit_type )
541
edittext->set_int_limits( low, high, limit_type );
545
/*********************************** GLUI_Spinner:reset_growth() *************/
547
void GLUI_Spinner::reset_growth( void )
551
if ( edittext->has_limits == GLUI_LIMIT_NONE ) {
552
if ( data_type == GLUI_SPINNER_FLOAT )
553
growth = sqrt(ABS(edittext->float_val)) * .05f;
554
else if ( data_type == GLUI_SPINNER_INT )
558
if ( data_type == GLUI_SPINNER_FLOAT ) {
559
lo = edittext->float_low;
560
hi = edittext->float_high;
561
growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS;
563
else if ( data_type == GLUI_SPINNER_INT ) {
564
lo = (float) edittext->int_low;
565
hi = (float) edittext->int_high;
567
growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS;
571
if ( growth == 0.0f )
576
/******************************* GLUI_Spinner:increase_growth() *************/
578
void GLUI_Spinner::increase_growth( void )
580
float hi = 0.0,lo = 0.0;
582
if ( data_type == GLUI_SPINNER_FLOAT ) {
583
lo = edittext->float_low;
584
hi = edittext->float_high;
586
else if ( data_type == GLUI_SPINNER_INT ) {
587
lo = (float) edittext->int_low;
588
hi = (float) edittext->int_high;
591
if ( growth < (hi-lo) / GLUI_SPINNER_MIN_GROWTH_STEPS )
592
growth *= growth_exp;
594
/* printf( "growth: %f\n", growth ); */
598
/*************************************** GLUI_Spinner:get_text() *************/
600
const char *GLUI_Spinner::get_text( void )
603
return edittext->text.c_str();
609
/********************************** GLUI_Spinner:get_float_val() *************/
611
float GLUI_Spinner::get_float_val( void )
614
return edittext->float_val;
620
/********************************** GLUI_Spinner:get_int_val() *************/
622
int GLUI_Spinner::get_int_val( void )
625
return edittext->int_val;