glui_spinner.cpp
上传用户:gb3593
上传日期:2022-01-07
资源大小:3028k
文件大小:18k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /****************************************************************************
  2.   
  3.   GLUI User Interface Toolkit
  4.   ---------------------------
  5.      glui_spinner.cpp - GLUI_Spinner class
  6.   notes: 
  7.      spinner does not explicitly keep track of the current value - this is all
  8.         handled by the underlying edittext control
  9.         -> thus, spinner->sync_live() has no meaning, nor spinner->output_live
  10. -> BUT, edittext will alter this spinner's float_val and int_val,
  11.    so that spinner->get/set will work
  12. FIXME: there's a heck of a lot of duplication between this and glui_scrollbar.cpp. 
  13.   (OSL, 2006/06)
  14.           --------------------------------------------------
  15.   Copyright (c) 1998 Paul Rademacher
  16.   WWW:    http://sourceforge.net/projects/glui/
  17.   Forums: http://sourceforge.net/forum/?group_id=92496
  18.   This library is free software; you can redistribute it and/or
  19.   modify it under the terms of the GNU Lesser General Public
  20.   License as published by the Free Software Foundation; either
  21.   version 2.1 of the License, or (at your option) any later version.
  22.   This library is distributed in the hope that it will be useful,
  23.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  24.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  25.   Lesser General Public License for more details.
  26.   You should have received a copy of the GNU Lesser General Public
  27.   License along with this library; if not, write to the Free Software
  28.   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  29. *****************************************************************************/
  30. #include "glui_internal_control.h"
  31. #include <cmath>
  32. #include <cassert>
  33. /*static int __debug=0;              */
  34. #define  GLUI_SPINNER_GROWTH_STEPS         800
  35. #define  GLUI_SPINNER_MIN_GROWTH_STEPS     100
  36. #define  GLUI_SPINNER_CALLBACK_INTERVAL    1
  37.  
  38. /****************************** spinner_edittext_callback() ******************/
  39. /*   This function is not used anymore.  It has been replaced by directly    */
  40. /*   Including an optional pointer to a spinner from an edittext box         */
  41. void  spinner_edittext_callback( int id )
  42. {
  43.   GLUI_Spinner *spinner;
  44.   putchar( '.' ); flushout;
  45.   
  46.   spinner = (GLUI_Spinner*) id;
  47.   if ( NOT spinner )
  48.     return;
  49.   spinner->do_callbacks();
  50. }
  51. /****************************** GLUI_Spinner::GLUI_Spinner() ****************/
  52. GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name, 
  53.                             int data_type, int id, GLUI_CB callback )
  54. {
  55.   common_construct(parent, name, data_type, NULL, id, callback);
  56. }
  57. /****************************** GLUI_Spinner::GLUI_Spinner() ****************/
  58. GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name, 
  59.                             int *live_var, int id, GLUI_CB callback )
  60. {
  61.   common_construct(parent, name, GLUI_SPINNER_INT, live_var, id, callback);
  62. }
  63. /****************************** GLUI_Spinner::GLUI_Spinner() ****************/
  64. GLUI_Spinner::GLUI_Spinner( GLUI_Node* parent, const char *name, 
  65.              float *live_var, int id, GLUI_CB callback )
  66. {
  67.   common_construct(parent, name, GLUI_SPINNER_FLOAT, live_var, id, callback);
  68. }
  69. /****************************** GLUI_Spinner::GLUI_Spinner() ****************/
  70. GLUI_Spinner::GLUI_Spinner( GLUI_Node *parent, const char *name, 
  71.                             int data_t, void *live_var,
  72.                             int id, GLUI_CB callback )
  73. {
  74.   common_construct(parent, name, data_t, live_var, id, callback);
  75. }
  76. /****************************** GLUI_Spinner::common_construct() ************/
  77. void GLUI_Spinner::common_construct( GLUI_Node* parent, const char *name, 
  78.                                      int data_t, void *data, 
  79.                                      int id, GLUI_CB cb )
  80. {
  81.   common_init();
  82.   if ( NOT strcmp( name, "Spinner Test" ))
  83.     id=id;
  84.   int text_type;
  85.   if ( data_t == GLUI_SPINNER_INT ) {
  86.     text_type = GLUI_EDITTEXT_INT;
  87.   }
  88.   else if ( data_t == GLUI_SPINNER_FLOAT ) {
  89.     text_type = GLUI_EDITTEXT_FLOAT;
  90.   }
  91.   else {
  92.     assert(0); /* Did not pass in a valid data type */
  93.   }
  94.   user_id     = id;
  95.   data_type   = data_t;
  96.   callback    = cb;
  97.   set_name( name );
  98.   //glui        = parent->get_glui();
  99.   parent->add_control( this );
  100.   GLUI_EditText *txt = 
  101.     new GLUI_EditText( this, name, text_type, data, id, cb);
  102.   edittext    = txt;  /* Link the edittext to the spinner */
  103.   /*      control->ptr_val     = data;               */
  104.     
  105.   edittext->spinner    = this; /* Link the spinner to the edittext */
  106.             
  107. }
  108.  
  109. /****************************** GLUI_Spinner::mouse_down_handler() **********/
  110. int    GLUI_Spinner::mouse_down_handler( int local_x, int local_y )
  111. {
  112.   this->state = find_arrow( local_x, local_y );
  113.   GLUI_Master.glui_setIdleFuncIfNecessary();
  114.   /*  printf( "spinner: mouse down  : %d/%d   arrow:%dn", local_x, local_y,
  115.       find_arrow( local_x, local_y ));
  116.       */
  117.   if ( state != GLUI_SPINNER_STATE_UP AND state != GLUI_SPINNER_STATE_DOWN )
  118.     return true;
  119.   reset_growth();
  120.   redraw();  
  121.   /*** ints and floats behave a bit differently.  When you click on
  122.     an int spinner, you expect the value to immediately go up by 1, whereas
  123.     for a float it'll go up only by a fractional amount.  Therefore, we
  124.     go ahead and increment by one for int spinners ***/
  125.   if ( data_type == GLUI_SPINNER_INT ) {
  126.     if ( state == GLUI_SPINNER_STATE_UP )
  127.       edittext->set_float_val( edittext->float_val + 1.0 );
  128.     else if ( state == GLUI_SPINNER_STATE_DOWN )
  129.       edittext->set_float_val( edittext->float_val - .9 );
  130.   }
  131.   
  132.   do_click();  
  133.   
  134.   return false;
  135. }
  136. /******************************** GLUI_Spinner::mouse_up_handler() **********/
  137. int    GLUI_Spinner::mouse_up_handler( int local_x, int local_y, bool inside )
  138. {
  139.   state = GLUI_SPINNER_STATE_NONE;
  140.   GLUI_Master.glui_setIdleFuncIfNecessary();
  141.   /*  printf("spinner: mouse up  : %d/%d    inside: %dn",local_x,local_y,inside);              */
  142.   /*glutSetCursor( GLUT_CURSOR_INHERIT );              */
  143.   glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
  144.   redraw();
  145.   /*  do_callbacks(); --- stub               */
  146.   /*  if ( callback )               */
  147.   /*  callback( this->user_id );              */
  148.   
  149.   return false;
  150. }
  151. /***************************** GLUI_Spinner::mouse_held_down_handler() ******/
  152. int    GLUI_Spinner::mouse_held_down_handler( int local_x, int local_y,
  153.       bool new_inside)
  154. {
  155.   int new_state;
  156.   if ( state == GLUI_SPINNER_STATE_NONE )
  157.     return false;
  158.   /*  printf("spinner: mouse held: %d/%d    inside: %dn",local_x,local_y,
  159.       new_inside);
  160.       */
  161.   if ( state == GLUI_SPINNER_STATE_BOTH ) {   /* dragging? */
  162.     do_drag( local_x, local_y );
  163.   }
  164.   else {                                      /* not dragging */
  165.     new_state = find_arrow( local_x, local_y );
  166.     
  167.     if ( new_state == state ) {
  168.       /** Still in same arrow **/
  169.       do_click();
  170.     }
  171.     else {
  172.       if ( new_inside OR 1) {
  173. /** The state changed, but we're still inside - that
  174.   means we moved off the arrow: begin dragging **/
  175. state = GLUI_SPINNER_STATE_BOTH;
  176.       }
  177.       else {
  178. /*** Here check y of mouse position to determine whether to 
  179.   drag ***/
  180. /* ... */
  181.       }
  182.     }
  183.     /*** We switched to up/down dragging ***/
  184.     if ( state == GLUI_SPINNER_STATE_BOTH ) {
  185.       glutSetCursor( GLUT_CURSOR_UP_DOWN );
  186.       last_x = local_x;
  187.       last_y = local_y;
  188.       /** If the spinner has limits, we reset the growth value, since
  189. reset_growth() will compute a new growth value for dragging
  190. vs. clicking.  If the spinner has no limits, then we just let the
  191. growth remain at whatever the user has incremented it up to **/
  192.       if ( edittext->has_limits != GLUI_LIMIT_NONE )
  193. reset_growth();
  194.     }
  195.     redraw();
  196.   }
  197.   return false;
  198. }
  199. /****************************** GLUI_Spinner::key_handler() **********/
  200. int    GLUI_Spinner::key_handler( unsigned char key,int modifiers )
  201. {
  202.   
  203.   return true;
  204. }
  205. /****************************** GLUI_Spinner::draw() **********/
  206. void    GLUI_Spinner::draw( int x, int y )
  207. {
  208.   GLUI_DRAWINGSENTINAL_IDIOM
  209.   if ( enabled ) {
  210.     /*** Draw the up arrow either pressed or unrpessed ***/
  211.     if ( state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_BOTH )
  212.       glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_ON, 
  213.       w-GLUI_SPINNER_ARROW_WIDTH-1, 
  214.       GLUI_SPINNER_ARROW_Y);
  215.     else
  216.       glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_OFF, 
  217.       w-GLUI_SPINNER_ARROW_WIDTH-1,
  218.       GLUI_SPINNER_ARROW_Y);
  219.     /*** Draw the down arrow either pressed or unrpessed ***/
  220.     if (state == GLUI_SPINNER_STATE_DOWN OR state == GLUI_SPINNER_STATE_BOTH)
  221.       glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_ON, 
  222.       w-GLUI_SPINNER_ARROW_WIDTH-1, 
  223.       GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y);
  224.     else
  225.       glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_OFF, 
  226.       w-GLUI_SPINNER_ARROW_WIDTH-1,
  227.       GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y);
  228.   }
  229.   else {  /**** The spinner is disabled ****/
  230.     glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_UP_DIS, 
  231.     w-GLUI_SPINNER_ARROW_WIDTH-1, 
  232.     GLUI_SPINNER_ARROW_Y);
  233.     glui->std_bitmaps.draw( GLUI_STDBITMAP_SPINNER_DOWN_DIS, 
  234.     w-GLUI_SPINNER_ARROW_WIDTH-1, 
  235.     GLUI_SPINNER_ARROW_HEIGHT+GLUI_SPINNER_ARROW_Y);
  236.   }
  237.   if ( active ) {
  238.     glColor3ub( 0, 0, 0 );
  239.     glEnable( GL_LINE_STIPPLE );
  240.     glLineStipple( 1, 0x5555 );
  241.   }
  242.   else {
  243.     glColor3ub( glui->bkgd_color.r,glui->bkgd_color.g,glui->bkgd_color.b );
  244.   } 
  245.   glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
  246.   glDisable( GL_CULL_FACE );
  247.   glBegin( GL_QUADS );
  248.   glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, 0 );
  249.   glVertex2i( w, 0 );
  250.   glVertex2i( w, h );
  251.   glVertex2i( w-GLUI_SPINNER_ARROW_WIDTH-2, h );
  252.   glEnd();
  253.   glDisable( GL_LINE_STIPPLE );  
  254.   glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  255. }
  256. /********************************* GLUI_Spinner::special_handler() **********/
  257. int    GLUI_Spinner::special_handler( int key,int modifiers )
  258. {
  259.   if ( key == GLUT_KEY_UP ) {    /** Simulate a click in the up arrow **/
  260.     mouse_down_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
  261. y_abs + GLUI_SPINNER_ARROW_Y+1 );
  262.     mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
  263.       y_abs + GLUI_SPINNER_ARROW_Y+1, true );
  264.   }
  265.   else if ( key == GLUT_KEY_DOWN ) {  /** Simulate a click in the up arrow **/
  266.     mouse_down_handler(x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
  267.        y_abs+GLUI_SPINNER_ARROW_Y+1+GLUI_SPINNER_ARROW_HEIGHT);
  268.     mouse_up_handler( x_abs + w - GLUI_SPINNER_ARROW_WIDTH + 1,
  269.       y_abs+GLUI_SPINNER_ARROW_Y+1 +GLUI_SPINNER_ARROW_HEIGHT,
  270.       true );
  271.   }
  272.   else if ( key == GLUT_KEY_HOME ) {  /** Set value to limit top - 
  273. or increment by 10 **/
  274.   }
  275.   else if ( key == GLUT_KEY_END ) {  
  276.   }
  277.   return true;
  278. }
  279. /******************************* GLUI_Spinner::set_float_val() ************/
  280. void   GLUI_Spinner::set_float_val( float new_val )
  281.   if ( NOT edittext )
  282.     return;
  283.   edittext->set_float_val( new_val );
  284. }
  285. /********************************** GLUI_Spinner::set_int_val() ************/
  286. void   GLUI_Spinner::set_int_val( int new_val )
  287. {
  288.   if ( NOT edittext )
  289.     return;
  290.   edittext->set_int_val( new_val );
  291. }
  292. /************************************ GLUI_Spinner::update_size() **********/
  293. void   GLUI_Spinner::update_size( void )
  294. {
  295.   if (!edittext) return;
  296.   /*edittext->w = this->w - GLUI_SPINNER_ARROW_WIDTH-3;              */
  297.   this->w = edittext->w + GLUI_SPINNER_ARROW_WIDTH + 3;
  298. }
  299.  
  300. /************************************ GLUI_Spinner::find_arrow() ************/
  301. int    GLUI_Spinner::find_arrow( int local_x, int local_y )
  302. {
  303.   local_x -= x_abs; 
  304.   local_y -= y_abs;
  305.  
  306.   if ( local_x >= (w - GLUI_SPINNER_ARROW_WIDTH) AND
  307.        local_x <= w ) {
  308.     if ( local_y >= GLUI_SPINNER_ARROW_Y AND 
  309.  local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT) )
  310.       return GLUI_SPINNER_STATE_UP;
  311.     if ( local_y >= GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT AND 
  312.  local_y <= (GLUI_SPINNER_ARROW_Y+GLUI_SPINNER_ARROW_HEIGHT*2) )
  313.       return GLUI_SPINNER_STATE_DOWN;
  314.   }
  315.   return GLUI_SPINNER_STATE_NONE;
  316. }
  317. /***************************************** GLUI_Spinner::do_click() **********/
  318. void    GLUI_Spinner::do_click( void )
  319. {
  320.   int    direction = 0;
  321.   float  incr;
  322.   float  modifier_factor;
  323.   if ( state == GLUI_SPINNER_STATE_UP )
  324.     direction = +1;
  325.   else if ( state == GLUI_SPINNER_STATE_DOWN )
  326.     direction = -1;
  327.   increase_growth();
  328.   modifier_factor = 1.0;
  329.   if ( glui ) {
  330.     if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT ) 
  331.       modifier_factor = 100.0f;
  332.     else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL ) 
  333.       modifier_factor = .01f;
  334.   }
  335.   if ( this->data_type == GLUI_SPINNER_FLOAT OR 1) {
  336.     incr = growth * direction * modifier_factor * user_speed;
  337.     edittext->set_float_val( edittext->float_val + incr );
  338.     /** Remember, edittext mirrors the float and int values ***/
  339.   }
  340.   /*** Now update live variable and do callback.  We don't want
  341.     to do the callback on each iteration of this function, just on every 
  342.     i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/
  343.   callback_count++;
  344.   if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 )
  345.     do_callbacks();
  346. }
  347. /***************************************** GLUI_Spinner::do_drag() **********/
  348. void    GLUI_Spinner::do_drag( int x, int y )
  349. {
  350.   int   delta_y;
  351.   float incr, modifier_factor;
  352.   /* int delta_x;              */
  353.   modifier_factor = 1.0f;
  354.   if ( glui ) {
  355.     if ( glui->curr_modifiers & GLUT_ACTIVE_SHIFT ) 
  356.       modifier_factor = 100.0f;
  357.     else if ( glui->curr_modifiers & GLUT_ACTIVE_CTRL ) 
  358.       modifier_factor = .01f;
  359.   }
  360.   /*  delta_x = x - last_x;              */
  361.   delta_y = -(y - last_y);
  362.  
  363.   if ( this->data_type == GLUI_SPINNER_FLOAT OR 1 ) {
  364.     incr = growth * delta_y * modifier_factor * user_speed;
  365.     edittext->set_float_val( edittext->float_val + incr );
  366.     /** Remember, edittext mirrors the float and int values ***/
  367.   }
  368.   last_x = x;
  369.   last_y = y;
  370.   /*** Now update live variable and do callback.  We don't want
  371.     to do the callback on each iteration of this function, just on every 
  372.     i^th iteration, where i is given by GLUI_SPINNER_CALLBACK_INTERVAL ****/
  373.   callback_count++;
  374.   if ( (callback_count % GLUI_SPINNER_CALLBACK_INTERVAL ) == 0 )
  375.     do_callbacks();
  376. }
  377. /***************************************** GLUI_Spinner::needs_idle() ******/
  378. bool GLUI_Spinner::needs_idle( void ) const
  379. {
  380.   if  (state == GLUI_SPINNER_STATE_UP OR state == GLUI_SPINNER_STATE_DOWN ) {
  381.     return true;
  382.   }
  383.   else {
  384.     return false;
  385.   }
  386. }
  387. /***************************************** GLUI_Spinner::idle() **********/
  388. void    GLUI_Spinner::idle( void )
  389. {
  390.   if ( NOT needs_idle() )
  391.     return;
  392.   else
  393.     do_click();
  394. }
  395. /************************************ GLUI_Spinner::do_callbacks() **********/
  396. void    GLUI_Spinner::do_callbacks( void )
  397. {
  398.   /*** This is not necessary, b/c edittext automatically updates us ***/
  399.   if ( NOT edittext )
  400.     return;
  401.   this->float_val = edittext->float_val;
  402.   this->int_val   = edittext->int_val;
  403.   /*    *******************************************/
  404.   if ( NOT first_callback ) {
  405.     if ( data_type == GLUI_SPINNER_INT AND int_val == last_int_val ) {
  406.       return;
  407.     }
  408.     
  409.     if ( data_type == GLUI_SPINNER_FLOAT AND float_val == last_float_val ) {
  410.       return;
  411.     }
  412.   }
  413.   
  414.   this->execute_callback();
  415.   last_int_val   = int_val;
  416.   last_float_val = float_val;
  417.   first_callback = false;
  418. }
  419. /********************************* GLUI_Spinner::set_float_limits() *********/
  420. void GLUI_Spinner::set_float_limits( float low, float high, int limit_type )
  421. {
  422.   if ( NOT edittext ) 
  423.     return;
  424.   edittext->set_float_limits( low, high, limit_type );
  425. }
  426. /*********************************** GLUI_Spinner::set_int_limits() *********/
  427. void   GLUI_Spinner::set_int_limits( int low, int high, int limit_type )
  428. {
  429.   if ( NOT edittext ) 
  430.     return;
  431.   
  432.   edittext->set_int_limits( low, high, limit_type );
  433. }
  434.  
  435. /*********************************** GLUI_Spinner:reset_growth() *************/
  436. void    GLUI_Spinner::reset_growth( void )
  437. {
  438.   float lo, hi;
  439.   if ( edittext->has_limits == GLUI_LIMIT_NONE ) {
  440.     if ( data_type == GLUI_SPINNER_FLOAT )
  441.       growth = sqrt(ABS(edittext->float_val)) * .05f;
  442.     else if ( data_type == GLUI_SPINNER_INT )
  443.       growth = .4f; 
  444.   }
  445.   else {
  446.     if ( data_type == GLUI_SPINNER_FLOAT ) {
  447.       lo = edittext->float_low;
  448.       hi = edittext->float_high;
  449.       growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS;
  450.     }
  451.     else if ( data_type == GLUI_SPINNER_INT ) {
  452.       lo = (float) edittext->int_low;
  453.       hi = (float) edittext->int_high;
  454.       
  455.       growth = (hi-lo) / GLUI_SPINNER_GROWTH_STEPS;
  456.     }
  457.   }
  458.   if ( growth == 0.0f )
  459.     growth = .001f;
  460. }
  461. /******************************* GLUI_Spinner:increase_growth() *************/
  462. void    GLUI_Spinner::increase_growth( void )
  463. {
  464.   float hi = 0.0,lo = 0.0;
  465.   if ( data_type == GLUI_SPINNER_FLOAT ) {
  466.     lo = edittext->float_low;
  467.     hi = edittext->float_high;
  468.   }
  469.   else if ( data_type == GLUI_SPINNER_INT ) {
  470.     lo = (float) edittext->int_low;
  471.     hi = (float) edittext->int_high;
  472.   }
  473.  
  474.   if ( growth < (hi-lo) / GLUI_SPINNER_MIN_GROWTH_STEPS )
  475.     growth *= growth_exp;
  476.   /*  printf( "growth: %fn", growth );              */
  477. }
  478. /*************************************** GLUI_Spinner:get_text() *************/
  479. const char    *GLUI_Spinner::get_text( void )
  480.   if (edittext) 
  481.     return edittext->text.c_str(); 
  482.   else 
  483.     return ""; 
  484. }
  485. /********************************** GLUI_Spinner:get_float_val() *************/
  486. float    GLUI_Spinner::get_float_val( void )
  487. {
  488.   if (edittext) 
  489.     return edittext->float_val; 
  490.   else 
  491.     return 0.0f; 
  492. }
  493. /********************************** GLUI_Spinner:get_int_val() *************/
  494. int    GLUI_Spinner::get_int_val( void )
  495. {
  496.   if (edittext) 
  497.     return edittext->int_val; 
  498.   else 
  499.     return 0; 
  500. }