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

游戏引擎

开发平台:

Visual C++

  1. /****************************************************************************
  2.   
  3.   GLUI User Interface Toolkit
  4.   ---------------------------
  5.      glui_edittext.cpp - GLUI_EditText control class
  6.           --------------------------------------------------
  7.   Copyright (c) 1998 Paul Rademacher
  8.   WWW:    http://sourceforge.net/projects/glui/
  9.   Forums: http://sourceforge.net/forum/?group_id=92496
  10.   This library is free software; you can redistribute it and/or
  11.   modify it under the terms of the GNU Lesser General Public
  12.   License as published by the Free Software Foundation; either
  13.   version 2.1 of the License, or (at your option) any later version.
  14.   This library is distributed in the hope that it will be useful,
  15.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17.   Lesser General Public License for more details.
  18.   You should have received a copy of the GNU Lesser General Public
  19.   License along with this library; if not, write to the Free Software
  20.   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21. *****************************************************************************/
  22. #include "glui_internal_control.h"
  23. #include <cassert>
  24. /****************************** GLUI_EditText::GLUI_EditText() **********/
  25. GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
  26.                              int data_type, void *live_var,
  27.                              int id, GLUI_CB callback )
  28. {
  29.   if (data_type == GLUI_EDITTEXT_TEXT) {
  30.     live_type = GLUI_LIVE_TEXT;
  31.   }
  32.   else if (data_type == GLUI_EDITTEXT_STRING) {
  33.    data_type = GLUI_EDITTEXT_TEXT;  // EDITTEXT_STRING doesn't really exist.
  34.                                      // Except as a signal to make a string.
  35.                                      // It's a backwards-compat hack.
  36.    live_type = GLUI_LIVE_STRING;
  37.   }
  38.   else if (data_type == GLUI_EDITTEXT_INT) {
  39.     live_type = GLUI_LIVE_INT;
  40.   }
  41.   else if (data_type == GLUI_EDITTEXT_FLOAT) {
  42.     live_type = GLUI_LIVE_FLOAT;
  43.   }
  44.   common_construct( parent, name, data_type, live_type, live_var, id, callback );
  45. }
  46. /****************************** GLUI_EditText::GLUI_EditText() **********/
  47. GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
  48.                               int text_type, int id, GLUI_CB callback )
  49. {
  50.   common_construct( parent, name, text_type, GLUI_LIVE_NONE, 0, id, callback);
  51. }
  52. /****************************** GLUI_EditText::GLUI_EditText() **********/
  53. GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
  54.                               int *live_var,
  55.                               int id, GLUI_CB callback )
  56. {
  57.   common_construct( parent, name, GLUI_EDITTEXT_INT, GLUI_LIVE_INT, live_var, id, callback);
  58. }
  59. /****************************** GLUI_EditText::GLUI_EditText() **********/
  60. GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
  61.                               float *live_var,
  62.                               int id, GLUI_CB callback )
  63. {
  64.   common_construct( parent, name, GLUI_EDITTEXT_FLOAT, GLUI_LIVE_FLOAT, live_var, id, callback);
  65. }
  66. /****************************** GLUI_EditText::GLUI_EditText() **********/
  67. GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, 
  68.                               char *live_var,
  69.                               int id, GLUI_CB callback )
  70. {
  71.   common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_TEXT, live_var, id, callback);
  72. }
  73. /****************************** GLUI_EditText::GLUI_EditText() **********/
  74. GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name, 
  75.                               std::string &live_var,
  76.                               int id, GLUI_CB callback )
  77. {
  78.   common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_STRING, &live_var, id, callback);
  79. }
  80. /****************************** GLUI_EditText::common_construct() **********/
  81. void GLUI_EditText::common_construct( GLUI_Node *parent, const char *name, 
  82.                                       int data_t, int live_t, void *data, int id, 
  83.                                       GLUI_CB cb )
  84. {
  85.   common_init();
  86.   set_name( name );
  87.     
  88.   live_type   = live_t;
  89.   data_type   = data_t;
  90.   ptr_val     = data;
  91.   user_id     = id;
  92.   callback    = cb;
  93.     
  94.   if ( live_type == GLUI_LIVE_INT) {
  95.     if ( data == NULL )
  96.       set_int_val(int_val);   /** Set to some default, in case of no live var **/
  97.   }
  98.   else if ( live_type == GLUI_LIVE_FLOAT ) {
  99.     num_periods = 1;
  100.     if ( data == NULL )
  101.       set_float_val(float_val);   /** Set to some default, in case of no live var **/
  102.   }
  103.   parent->add_control( this );
  104.   init_live();
  105. }
  106. /****************************** GLUI_EditText::mouse_down_handler() **********/
  107. int    GLUI_EditText::mouse_down_handler( int local_x, int local_y )
  108. {
  109.   int tmp_insertion_pt;
  110.   if ( debug )    dump( stdout, "-> MOUSE DOWN" );
  111.   tmp_insertion_pt = find_insertion_pt( local_x, local_y );  
  112.   if ( tmp_insertion_pt == -1 ) {
  113.     if ( glui )
  114.       glui->deactivate_current_control(  );
  115.     return false;
  116.   }
  117.   insertion_pt = tmp_insertion_pt;
  118.   sel_start = sel_end = insertion_pt;
  119.   if ( can_draw())
  120.     update_and_draw_text();
  121.   if ( debug )    dump( stdout, "<- MOUSE UP" );
  122.   return true;
  123. }
  124. /******************************** GLUI_EditText::mouse_up_handler() **********/
  125. int    GLUI_EditText::mouse_up_handler( int local_x, int local_y, bool inside )
  126. {
  127.   return false;
  128. }
  129. /***************************** GLUI_EditText::mouse_held_down_handler() ******/
  130. int    GLUI_EditText::mouse_held_down_handler( int local_x, int local_y,
  131.        bool new_inside)
  132. {
  133.   int tmp_pt;
  134.   if ( NOT new_inside ) 
  135.     return false;
  136.   if ( debug )    dump( stdout, "-> HELD DOWN" );
  137.   
  138.   tmp_pt = find_insertion_pt( local_x, local_y );
  139.   
  140.   if ( tmp_pt == -1 AND sel_end != 0 ) {    /* moved mouse past left edge */
  141.     special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT );
  142.   }
  143.   else if ( tmp_pt == substring_end+1 AND sel_end != (int) text.length()) {    
  144.     /* moved mouse past right edge */
  145.     special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT );    
  146.   }
  147.   else if ( tmp_pt != -1 AND tmp_pt != sel_end ) {
  148.     sel_end = insertion_pt = tmp_pt;
  149.     
  150.     update_and_draw_text();
  151.   }
  152.   if ( debug )
  153.     dump( stdout, "<- HELD DOWN" );
  154.   return false;
  155. }
  156. /****************************** GLUI_EditText::key_handler() **********/
  157. int    GLUI_EditText::key_handler( unsigned char key,int modifiers )
  158. {
  159.   int i, regular_key;
  160.   /* int has_selection;              */
  161.   if ( NOT glui )
  162.     return false;
  163.   if ( debug )
  164.     dump( stdout, "-> KEY HANDLER" );
  165.   regular_key = false;
  166.   bool ctrl_down = (modifiers & GLUT_ACTIVE_CTRL)!=0;
  167.   /*  has_selection = (sel_start != sel_end);              */
  168.   if ( key == CTRL('m') ) {           /* RETURN */
  169.     /*    glui->deactivate_current_control();              */
  170.     deactivate();  /** Force callbacks, etc **/
  171.     activate(GLUI_ACTIVATE_TAB);     /** Reselect all text **/
  172.     redraw();
  173.     return true;
  174.   }
  175.   else if ( key  == CTRL('[')) {         /* ESCAPE */
  176.     glui->deactivate_current_control();
  177.     return true;
  178.   }
  179.   else if ( (key == 127 AND !ctrl_down) OR  /* FORWARD DELETE */
  180.             ( key == CTRL('d') AND modifiers == GLUT_ACTIVE_CTRL) ) 
  181.   {
  182.     if ( sel_start == sel_end ) {   /* no selection */
  183.       if ( insertion_pt < (int)text.length() ) {
  184.         /*** See if we're deleting a period in a float data-type box ***/
  185.         if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt]=='.' )
  186.           num_periods--;
  187.         /*** Shift over string first ***/
  188.         text.erase(insertion_pt,1);
  189.       }
  190.     }
  191.     else {                         /* There is a selection */
  192.       clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
  193.       insertion_pt = MIN(sel_start,sel_end);
  194.       sel_start = sel_end = insertion_pt;
  195.     }
  196.   }
  197.   else if ( ((key == 127) AND ctrl_down) OR   // Delete word forward
  198.             ((key == 'd') AND (modifiers == GLUT_ACTIVE_ALT)) )
  199.   {
  200.     if ( sel_start == sel_end ) {   /* no selection */
  201.       sel_start = insertion_pt;
  202.       sel_end = find_word_break( insertion_pt, +1 );
  203.     }
  204.     clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
  205.     insertion_pt = MIN(sel_start,sel_end);
  206.     sel_start = sel_end = insertion_pt;
  207.   }
  208.   else if ( key == CTRL('h') ) {       /* BACKSPACE */
  209.     if ( sel_start == sel_end ) {   /* no selection */
  210.       if ( insertion_pt > 0 ) {
  211.         /*** See if we're deleting a period in a float data-type box ***/
  212.         if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt-1]=='.' )
  213.           num_periods--;
  214.         /*** Shift over string first ***/
  215.         insertion_pt--;
  216.         text.erase(insertion_pt,1);
  217.       }
  218.     }
  219.     else {                         /* There is a selection */
  220.       clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
  221.       insertion_pt = MIN(sel_start,sel_end);
  222.       sel_start = sel_end = insertion_pt;
  223.     }
  224.   }
  225.   else if ( modifiers == GLUT_ACTIVE_CTRL )  /* CTRL ONLY */ 
  226.   {
  227.     /* Ctrl-key bindings */
  228.     if ( key == CTRL('a') ) {
  229.       return special_handler( GLUT_KEY_HOME, 0 );
  230.     }
  231.     else if ( key == CTRL('e') ) {
  232.       return special_handler( GLUT_KEY_END, 0 );
  233.     }
  234.     else if ( key == CTRL('b') ) {
  235.       return special_handler( GLUT_KEY_LEFT, 0 );
  236.     }
  237.     else if ( key == CTRL('f') ) {
  238.       return special_handler( GLUT_KEY_RIGHT, 0 );
  239.     }
  240.     else if ( key == CTRL('p') ) {
  241.       return special_handler( GLUT_KEY_UP, 0 );
  242.     }
  243.     else if ( key == CTRL('n') ) {
  244.       return special_handler( GLUT_KEY_DOWN, 0 );
  245.     }
  246.     else if ( key == CTRL('u') ) { /* ERASE LINE */
  247.       insertion_pt = 0;  
  248.       text.erase(0,text.length());
  249.       sel_start = sel_end = 0;
  250.     }
  251.     else if ( key == CTRL('k') ) { /* KILL TO END OF LINE */
  252.       sel_start = sel_end = insertion_pt;
  253.       text.erase(insertion_pt,GLUI_String::npos);
  254.     }
  255.   }
  256.   else if ( modifiers == GLUT_ACTIVE_ALT ) /* ALT ONLY */
  257.   {
  258.     if ( key == 'b' ) { // Backward word
  259.       return special_handler ( GLUT_KEY_LEFT, GLUT_ACTIVE_CTRL );
  260.     }
  261.     if ( key == 'f' ) { // Forward word
  262.       return special_handler ( GLUT_KEY_RIGHT, GLUT_ACTIVE_CTRL );
  263.     }
  264.   }
  265.   else if ( (modifiers & GLUT_ACTIVE_CTRL) OR
  266.             (modifiers & GLUT_ACTIVE_ALT) ) 
  267.   {
  268.     /** ignore other keys with modifiers */
  269.     return true;
  270.   }
  271.   else { /* Regular key */    
  272.     regular_key = true;
  273.     /** Check if we only accept numbers **/
  274.     if (data_type == GLUI_EDITTEXT_FLOAT ) {
  275.       if ( (key < '0' OR key > '9') AND key != '.' AND key != '-' )
  276.         return true;
  277.       if ( key == '-' ) { /* User typed a '-' */
  278.         /* If user has first character selected, then '-' is allowed */
  279.         if ( NOT ( MIN(sel_start,sel_end) == 0 AND
  280.                    MAX(sel_start,sel_end) > 0 ) ) {
  281.           /* User does not have 1st char selected */
  282.           if (insertion_pt != 0 OR text[0] == '-' ) {
  283.             return true; /* Can only place negative at beginning of text,
  284.                             and only one of them */
  285.           }
  286.         }
  287.       }
  288.       if ( key == '.' ) {
  289.         /*printf( "PERIOD: %dn", num_periods );              */
  290.         if ( num_periods > 0 ) {
  291.           /** We're trying to type a period, but the text already contains
  292.           a period.  Check whether the period is contained within
  293.           is current selection (thus it will be safely replaced) **/
  294.           int period_found = false; 
  295.           if ( sel_start != sel_end ) {
  296.             for( i=MIN(sel_end,sel_start); i<MAX(sel_start,sel_end); i++ ) {
  297.               /*  printf( "%c ", text[i] );              */
  298.               if ( text[i] == '.' ) {
  299.                 period_found = true;
  300.                 break;
  301.               }
  302.             }
  303.           }
  304.           /* printf( "found: %d    num: %dn", period_found, num_periods );              */
  305.           if ( NOT period_found )
  306.             return true;
  307.         }
  308.       }
  309.     } 
  310.     else if (data_type == GLUI_EDITTEXT_INT)
  311.     {
  312.       if ( (key < '0' OR key > '9') AND key != '-' )
  313.         return true;
  314.       if ( key == '-' ) { /* User typed a '-' */
  315.         /* If user has first character selected, then '-' is allowed */
  316.         if ( NOT ( MIN(sel_start,sel_end) == 0 AND
  317.           MAX(sel_start,sel_end) > 0 ) ) {
  318.             /* User does not have 1st char selected */
  319.             if (insertion_pt != 0 OR text[0] == '-' ) {
  320.               return true; /* Can only place negative at beginning of text,
  321.                            and only one of them */
  322.             }
  323.           }
  324.       }
  325.     }
  326.     /** This is just to get rid of warnings - the flag regular_key is 
  327.       set if the key was not a backspace, return, whatever.  But I
  328.       believe if we're here, we know it was a regular key anyway */
  329.     if ( regular_key ) {
  330.     }
  331.     /**** If there's a current selection, erase it ******/
  332.     if ( sel_start != sel_end ) {
  333.       clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
  334.       insertion_pt = MIN(sel_start,sel_end);
  335.       sel_start = sel_end = insertion_pt;
  336.     }
  337.     /******** We insert the character into the string ***/
  338.     text.insert(insertion_pt,1,key);
  339.     /******** Move the insertion point and substring_end one over ******/
  340.     insertion_pt++;
  341.     substring_end++;
  342.     sel_start = sel_end = insertion_pt;
  343.   }
  344.   /******** Now redraw text ***********/
  345.   /* Hack to prevent text box from being cleared first **/  
  346.   /**  int substring_change =  update_substring_bounds();
  347.   draw_text_only = 
  348.   (NOT substring_change AND NOT has_selection AND regular_key ); 
  349.   */
  350.   draw_text_only = false;  /** Well, hack is not yet working **/
  351.   update_and_draw_text();
  352.   draw_text_only = false;
  353.   if ( debug )
  354.     dump( stdout, "<- KEY HANDLER" );
  355.   /*** Now look to see if this string has a period ***/
  356.   num_periods = 0;
  357.   for( i=0; i<(int)text.length(); i++ )
  358.     if ( text[i] == '.' )
  359.       num_periods++;
  360.   return true;
  361. }
  362. /****************************** GLUI_EditText::activate() **********/
  363. void    GLUI_EditText::activate( int how )
  364. {
  365.   if ( debug )
  366.     dump( stdout, "-> ACTIVATE" );
  367.   active = true;
  368.   if ( how == GLUI_ACTIVATE_MOUSE )
  369.     return;  /* Don't select everything if activated with mouse */
  370.   orig_text = text;
  371.   sel_start    = 0;
  372.   sel_end      = (int)text.length();
  373.   insertion_pt = 0;
  374.   if ( debug )
  375.     dump( stdout, "<- ACTIVATE" );
  376. }
  377. /****************************** GLUI_EditText::deactivate() **********/
  378. void    GLUI_EditText::deactivate( void )
  379. {
  380.   int    new_int_val;
  381.   float  new_float_val;
  382.   active = false;
  383.   if ( NOT glui )
  384.     return;
  385.   if ( debug )
  386.     dump( stdout, "-> DISACTIVATE" );
  387.   sel_start = sel_end = insertion_pt = -1; 
  388.   /***** Retrieve the current value from the text *****/
  389.   /***** The live variable will be updated by set_text() ****/
  390.   if ( data_type == GLUI_EDITTEXT_FLOAT ) {
  391.     if ( text.length() == 0 ) /* zero-length string - make it "0.0" */
  392.       text = "0.0";
  393.     new_float_val = atof( text.c_str() );
  394.     set_float_val( new_float_val );
  395.   }
  396.   else if ( data_type == GLUI_EDITTEXT_INT ) {
  397.     if ( text.length() == 0 ) /* zero-length string - make it "0" */
  398.       text = "0";
  399.     new_int_val = atoi( text.c_str() );
  400.     set_int_val( new_int_val );
  401.   }
  402.   else 
  403.     if ( data_type == GLUI_EDITTEXT_TEXT ) {
  404.       set_text(text); /* This will force callbacks and gfx refresh */
  405.     }
  406.   update_substring_bounds();
  407.   /******** redraw text without insertion point ***********/
  408.   redraw();
  409.   /***** Now do callbacks if value changed ******/
  410.   if ( orig_text != text ) {
  411.     this->execute_callback();
  412.     
  413.     if ( 0 ) {
  414.       /* THE CODE BELOW IS FROM WHEN SPINNER ALSO MAINTAINED CALLBACKS    */
  415.       if ( spinner == NULL ) {   /** Are we independent of a spinner?  **/  
  416.         if ( callback ) {
  417.           callback( this );              
  418.         }              
  419.       }              
  420.       else {                      /* We're attached to a spinner */              
  421.         spinner->do_callbacks();  /* Let the spinner do the callback stuff */  
  422.       }              
  423.     }
  424.   }
  425.   if ( debug )
  426.     dump( stdout, "<- DISACTIVATE" );
  427. }
  428. /****************************** GLUI_EditText::draw() **********/
  429. void    GLUI_EditText::draw( int x, int y )
  430. {
  431.   GLUI_DRAWINGSENTINAL_IDIOM
  432.   int name_x;
  433.   name_x = MAX(text_x_offset - string_width(this->name) - 3,0);
  434.   draw_name( name_x , 13);
  435.   glBegin( GL_LINES );
  436.   glColor3f( .5, .5, .5 );
  437.   glVertex2i( text_x_offset, 0 );     glVertex2i( w, 0 );
  438.   glVertex2i( text_x_offset, 0 );     glVertex2i( text_x_offset, h );     
  439.   glColor3f( 1., 1., 1. );
  440.   glVertex2i( text_x_offset, h );     glVertex2i( w, h );
  441.   glVertex2i( w, h );                 glVertex2i( w, 0 );
  442.   if ( enabled )
  443.     glColor3f( 0., 0., 0. );
  444.   else
  445.     glColor3f( .25, .25, .25 );
  446.   glVertex2i( text_x_offset+1, 1 );     glVertex2i( w-1, 1 );
  447.   glVertex2i( text_x_offset+1, 1 );     glVertex2i( text_x_offset+1, h-1 );
  448.   glColor3f( .75, .75, .75 );
  449.   glVertex2i( text_x_offset+1, h-1 );     glVertex2i( w-1, h-1 );
  450.   glVertex2i( w-1, h-1 );                 glVertex2i( w-1, 1 );
  451.   glEnd();
  452.   /** Find where to draw the text **/
  453.   update_substring_bounds();
  454.   draw_text(0,0);
  455.   
  456.   draw_insertion_pt();
  457. }
  458. /************************** GLUI_EditText::update_substring_bounds() *********/
  459. int    GLUI_EditText::update_substring_bounds( void )
  460. {
  461.   int box_width;
  462.   int text_len = (int)text.length();
  463.   int old_start, old_end;
  464.   old_start = substring_start;
  465.   old_end = substring_end;
  466.   /*** Calculate the width of the usable area of the edit box ***/
  467.   box_width = MAX( this->w - this->text_x_offset 
  468.    - 4     /*  2 * the two-line box border */ 
  469.    - 2 * GLUI_EDITTEXT_BOXINNERMARGINX, 0 );
  470.   CLAMP( substring_end, 0, MAX(text_len-1,0) );
  471.   CLAMP( substring_start, 0, MAX(text_len-1,0) );
  472.   if ( debug )    dump( stdout, "-> UPDATE SS" );
  473.   if ( insertion_pt >= 0 AND 
  474.        insertion_pt < substring_start ) {   /* cursor moved left */
  475.     substring_start = insertion_pt;
  476.     while ( substring_width( substring_start, substring_end ) > box_width )
  477.       substring_end--;
  478.   }
  479.   else if ( insertion_pt > substring_end ) {  /* cursor moved right */
  480.     substring_end = insertion_pt-1;
  481.     while ( substring_width( substring_start, substring_end ) > box_width )
  482.       substring_start++;
  483.   }
  484.   else {   /* cursor is within old substring bounds */
  485.     if ( last_insertion_pt > insertion_pt ) {  /* cursor moved left */
  486.     }
  487.     else {
  488.       while ( substring_width( substring_start, substring_end ) > box_width )
  489. substring_end--;
  490.       while(substring_end < text_len-1 
  491.             AND substring_width( substring_start, substring_end ) <= box_width)
  492.        substring_end++;
  493.     }
  494.   }
  495.   while ( substring_width( substring_start, substring_end ) > box_width )
  496.     substring_end--;
  497.   last_insertion_pt = insertion_pt;
  498.   /*** No selection if not enabled ***/
  499.   if ( NOT enabled ) {
  500.     sel_start = sel_end = 0;
  501.   }
  502.   if ( debug )    dump( stdout, "<- UPDATE SS" );
  503.   if ( substring_start == old_start AND substring_end == old_end )
  504.     return false;  /*** bounds did not change ***/
  505.   else 
  506.     return true;   /*** bounds did change ***/
  507. }
  508. /********************************* GLUI_EditText::update_x_offsets() *********/
  509. void    GLUI_EditText::update_x_offsets( void )
  510. {
  511. }
  512.  
  513. /********************************* GLUI_EditText::draw_text() ****************/
  514. void    GLUI_EditText::draw_text( int x, int y )
  515. {
  516.   GLUI_DRAWINGSENTINAL_IDIOM
  517.   int text_x, i, sel_lo, sel_hi;
  518.   if ( debug )    dump( stdout, "-> DRAW_TEXT" );
  519.   if ( NOT draw_text_only ) {
  520.     if ( enabled )
  521.       glColor3f( 1., 1., 1. );
  522.     else
  523.       set_to_bkgd_color();
  524.     glDisable( GL_CULL_FACE );
  525.     glBegin( GL_QUADS );
  526.     glVertex2i( text_x_offset+2, 2 );     glVertex2i( w-2, 2 );
  527.     glVertex2i( w-2, h-2 );               glVertex2i( text_x_offset+2, h-2 );
  528.     glEnd();
  529.   }
  530.   /** Find where to draw the text **/
  531.   text_x = text_x_offset + 2 + GLUI_EDITTEXT_BOXINNERMARGINX;
  532.   /*printf( "text_x: %d      substr_width: %d     start/end: %d/%dn",
  533.     text_x,     substring_width( substring_start, substring_end ),
  534.     substring_start, substring_end );
  535.     */
  536.   /** Find lower and upper selection bounds **/
  537.   sel_lo = MIN(sel_start, sel_end );
  538.   sel_hi = MAX(sel_start, sel_end );
  539.   int sel_x_start, sel_x_end, delta;
  540.   /** Draw selection area dark **/
  541.   if ( sel_start != sel_end ) {
  542.     sel_x_start = text_x;
  543.     sel_x_end   = text_x;
  544.     for( i=substring_start; i<=substring_end; i++ ) {
  545.       delta = char_width( text[i] );
  546.       if ( i < sel_lo ) {
  547. sel_x_start += delta;
  548. sel_x_end   += delta;
  549.       }
  550.       else if ( i < sel_hi ) {
  551. sel_x_end   += delta;
  552.       }
  553.     }
  554.     glColor3f( 0.0f, 0.0f, .6f );
  555.     glBegin( GL_QUADS );
  556.     glVertex2i( sel_x_start, 2 );    glVertex2i( sel_x_end, 2 );
  557.     glVertex2i( sel_x_end, h-2 );    glVertex2i( sel_x_start, h-2 );
  558.     glEnd();
  559.   }
  560.    
  561.   if ( sel_start == sel_end ) {   /* No current selection */
  562.     if ( enabled )
  563.       glColor3b( 0, 0, 0 );
  564.     else
  565.       glColor3b( 32, 32, 32 );
  566.       
  567.     glRasterPos2i( text_x, 13);
  568.     for( i=substring_start; i<=substring_end; i++ ) {
  569.       glutBitmapCharacter( get_font(), this->text[i] );
  570.     }
  571.   }
  572.   else {                          /* There is a selection */
  573.     int x = text_x;
  574.     for( i=substring_start; i<=substring_end; i++ ) {
  575.       if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { /* This character is selected */
  576. glColor3f( 1., 1., 1. );
  577. glRasterPos2i( x, 13);
  578. glutBitmapCharacter( get_font(), this->text[i] );
  579.       }
  580.       else {
  581. glColor3f( 0., 0., 0. );
  582. glRasterPos2i( x, 13);
  583. glutBitmapCharacter( get_font(), this->text[i] );
  584.       }
  585.       
  586.       x += char_width( text[i] );
  587.     }
  588.   }
  589.   if ( debug )    dump( stdout, "<- DRAW_TEXT" );  
  590. }
  591. /******************************** GLUI_EditText::find_insertion_pt() *********/
  592. /* This function returns the character numer *before which* the insertion    */
  593. /* point goes                                                                */
  594. int  GLUI_EditText::find_insertion_pt( int x, int y )
  595. {
  596.   int curr_x, i;
  597.   /*** See if we clicked outside box ***/
  598.   if ( x < this->x_abs + text_x_offset )
  599.     return -1;
  600.   /* We move from right to left, looking to see if the mouse was clicked
  601.      to the right of the ith character */
  602.   curr_x = this->x_abs + text_x_offset 
  603.     + substring_width( substring_start, substring_end )
  604.     + 2                             /* The edittext box has a 2-pixel margin */
  605.     + GLUI_EDITTEXT_BOXINNERMARGINX;   /** plus this many pixels blank space
  606.  between the text and the box       **/
  607.   /*** See if we clicked in an empty box ***/
  608.   if ( (int) text.length() == 0 ) 
  609.     return 0;
  610.   /** find mouse click in text **/
  611.   for( i=substring_end; i>=substring_start; i-- ) {
  612.     curr_x -= char_width( text[i] );
  613.     if ( x > curr_x ) {
  614.       /*      printf( "-> %dn", i );              */
  615.       
  616.       return i+1;
  617.     }
  618.   }
  619.   return 0;
  620.   /* Well, the mouse wasn't after any of the characters...see if it's
  621.      before the beginning of the substring */
  622.   if ( 0 ) {
  623.     if ( x > (x_abs + text_x_offset + 2 ) )
  624.       return substring_start;
  625.     
  626.     return -1; /* Nothing found */
  627.   }
  628. }
  629. /******************************** GLUI_EditText::draw_insertion_pt() *********/
  630. void     GLUI_EditText::draw_insertion_pt( void )
  631. {
  632.   int curr_x, i;
  633.   if ( NOT can_draw() )
  634.     return;
  635.   /*** Don't draw insertion pt if control is disabled ***/
  636.   if ( NOT enabled )
  637.     return;
  638.   if ( debug )    dump( stdout, "-> DRAW_INS_PT" );
  639.   if ( sel_start != sel_end OR insertion_pt < 0 ) {
  640.     return;  /* Don't draw insertion point if there is a current selection */
  641.   }
  642.   /*    printf( "insertion pt: %dn", insertion_pt );              */
  643.   curr_x = this->x_abs + text_x_offset 
  644.     + substring_width( substring_start, substring_end )
  645.     + 2                             /* The edittext box has a 2-pixel margin */
  646.     + GLUI_EDITTEXT_BOXINNERMARGINX;   /** plus this many pixels blank space
  647.  between the text and the box       **/
  648.   for( i=substring_end; i>=insertion_pt; i-- ) {
  649.     curr_x -= char_width( text[i] ); 
  650.   }  
  651.   glColor3f( 0.0, 0.0, 0.0 );
  652.   glBegin( GL_LINE_LOOP );
  653.   /***
  654.     glVertex2i( curr_x, y_abs + 4 );
  655.     glVertex2i( curr_x, y_abs + 4 );
  656.     glVertex2i( curr_x, y_abs + h - 3 );
  657.     glVertex2i( curr_x, y_abs + h - 3 );
  658.     ***/
  659.   curr_x -= x_abs;
  660.   glVertex2i( curr_x, 0 + 4 );
  661.   glVertex2i( curr_x, 0 + 4 );
  662.   glVertex2i( curr_x, 0 + h - 3 );
  663.   glVertex2i( curr_x, 0 + h - 3 );
  664.   glEnd();
  665.   if ( debug )    dump( stdout, "-> DRAW_INS_PT" );
  666. }
  667. /******************************** GLUI_EditText::substring_width() *********/
  668. int  GLUI_EditText::substring_width( int start, int end )
  669. {
  670.   int i, width;
  671.   width = 0;
  672.   for( i=start; i<=end; i++ )
  673.     width += char_width( text[i] ); 
  674.   return width;
  675. }
  676.  
  677. /***************************** GLUI_EditText::update_and_draw_text() ********/
  678. void   GLUI_EditText::update_and_draw_text( void )
  679. {
  680.   if ( NOT can_draw() )
  681.     return;
  682.   update_substring_bounds();
  683.   /*  printf( "ss: %d/%dn", substring_start, substring_end );                  */
  684.   redraw();
  685. }
  686. /********************************* GLUI_EditText::special_handler() **********/
  687. int    GLUI_EditText::special_handler( int key,int modifiers )
  688. {
  689.   if ( NOT glui )
  690.     return false;
  691.   
  692.   if ( debug )
  693.     printf( "SPECIAL:%d - mod:%d   subs:%d/%d  ins:%d  sel:%d/%dn", 
  694.     key, modifiers, substring_start, substring_end,insertion_pt,
  695.     sel_start, sel_end );  
  696.   if ( key == GLUT_KEY_LEFT ) {
  697.     if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
  698.       insertion_pt = find_word_break( insertion_pt, -1 );
  699.     }
  700.     else {
  701.       insertion_pt--;
  702.     }
  703.   }
  704.   else if ( key == GLUT_KEY_RIGHT ) {
  705.     if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
  706.       insertion_pt = find_word_break( insertion_pt, +1 );
  707.     }
  708.     else {
  709.       insertion_pt++;
  710.     }
  711.   }
  712.   else if ( key == GLUT_KEY_HOME ) {
  713.     insertion_pt = 0;
  714.   }
  715.   else if ( key == GLUT_KEY_END ) {
  716.     insertion_pt = (int) text.length();
  717.   }
  718.   /*** Update selection if shift key is down ***/
  719.   if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 )
  720.     sel_end = insertion_pt;
  721.   else 
  722.     sel_start = sel_end = insertion_pt;
  723.   
  724.   CLAMP( insertion_pt, 0, (int) text.length()); /* Make sure insertion_pt 
  725.                                       is in bounds */
  726.   CLAMP( sel_start, 0, (int) text.length()); /* Make sure insertion_pt 
  727.                                     is in bounds */
  728.   CLAMP( sel_end, 0, (int) text.length()); /* Make sure insertion_pt 
  729.                                      is in bounds */
  730.       
  731.   /******** Now redraw text ***********/
  732.   if ( can_draw())
  733.     update_and_draw_text();
  734.   return true;
  735. }
  736. /****************************** GLUI_EditText::find_word_break() **********/
  737. /* It looks either left or right (depending on value of 'direction'       */
  738. /* for the beginning of the next 'word', where word are characters        */
  739. /* separated by one of the following tokens:  " :-.,"                     */
  740. /* If there is no next word in the specified direction, this returns      */
  741. /* the beginning of 'text', or the very end.                              */
  742. int    GLUI_EditText::find_word_break( int start, int direction )
  743. {
  744.   int    i, j;
  745.   char   *breaks = " :-.,";
  746.   int     num_break_chars = (int)strlen(breaks), text_len = (int)text.length();
  747.   int     new_pt;
  748.   /** If we're moving left, we have to start two back, in case we're either
  749.   already at the beginning of a word, or on a separating token.  
  750.   Otherwise, this function would just return the word we're already at **/
  751.   if ( direction == -1 ) {
  752.     start -= 2;
  753.   }
  754.   /***** Iterate over text in the specified direction *****/
  755.   for ( i=start; i >= 0 AND i < text_len; i += direction ) {
  756.     /** For each character in text, iterate over list of separating tokens **/
  757.     for( j=0; j<num_break_chars; j++ ) {
  758.       if ( text[i] == breaks[j] ) {
  759.         /** character 'i' is a separating token, so we return i+1 **/
  760.         new_pt = i + 1;
  761.         CLAMP( new_pt, 0, text_len );
  762.         return new_pt;
  763.       }
  764.     }
  765.   }
  766.   if ( direction > 0 )  /* Return the end of string */
  767.     return text_len;
  768.   else                  /* Return the beginning of the text */
  769.     return 0;
  770. }
  771. /********************************** GLUI_EditText::clear_substring() ********/
  772. void   GLUI_EditText::clear_substring( int start, int end )
  773. {
  774.   int i;
  775.   /*
  776.   printf( "clearing: %d-%d   '", start,end);
  777.   for(i=start;i<end;i++ )
  778.   putchar(text[i]);
  779.   printf( "'n" ); flushout;
  780.   */
  781.   /*** See if we're deleting a period in a float data-type box ***/
  782.   if ( data_type == GLUI_EDITTEXT_FLOAT ) {
  783.     for( i=start; i<end; i++ )
  784.       if ( text[i] == '.' )
  785.         num_periods = 0;
  786.   }
  787.   text.erase(start,end-start);
  788. }
  789. /************************************ GLUI_EditText::update_size() **********/
  790. void   GLUI_EditText::update_size( void )
  791. {
  792.   int text_size, delta;
  793.   if ( NOT glui )
  794.     return;
  795.   text_size = string_width( name );
  796.   delta = 0;
  797.   if ( text_x_offset < text_size +2 )
  798.     delta = text_size+2-text_x_offset;
  799.   text_x_offset += delta;
  800.   /*  w += delta;              */
  801.   if ( data_type == GLUI_EDITTEXT_TEXT OR 
  802.        data_type == GLUI_EDITTEXT_FLOAT) {
  803.     if ( w < text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH )
  804.       w = text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH;
  805.   }
  806.   else if ( data_type == GLUI_EDITTEXT_INT ) {
  807.     if ( w < text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH )
  808.       w = text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH;
  809.   }
  810. }
  811. /****************************** GLUI_EditText::set_text() **********/
  812. void    GLUI_EditText::set_text( const char *new_text )
  813. {
  814.   text=new_text;
  815.   substring_start = 0;
  816.   substring_end   = (int) text.length() - 1;
  817.   insertion_pt    = -1;
  818.   sel_start       = 0;
  819.   sel_end         = 0;
  820.   if ( can_draw() )
  821.     update_and_draw_text();
  822.   /** Update the spinner, if we have one **/
  823.   if ( spinner ) {
  824.     spinner->float_val = this->float_val;
  825.     spinner->int_val   = this->int_val;
  826.   }
  827.   /*** Now update the live variable ***/
  828.   output_live(true);
  829. }
  830. /******************************* GLUI_EditText::set_float_val() ************/
  831. void   GLUI_EditText::set_float_val( float new_val )
  832. {
  833.   if ( has_limits == GLUI_LIMIT_CLAMP ) {
  834.     /*** Clamp the new value to the existing limits ***/
  835.     CLAMP( new_val, float_low, float_high );
  836.   } 
  837.   else if ( has_limits == GLUI_LIMIT_WRAP ) {
  838.     /*** Clamp the value cyclically to the limits - that is, if the
  839.       value exceeds the max, set it the the minimum, and conversely ***/
  840.     if ( new_val < float_low )
  841.       new_val = float_high;
  842.     if ( new_val > float_high )
  843.       new_val = float_low;
  844.   }
  845.   float_val = new_val;
  846.   int_val   = (int) new_val;  /* Mirror the value as an int, too */
  847.   
  848.   set_numeric_text();
  849. }
  850. /********************************** GLUI_EditText::set_int_val() ************/
  851. void   GLUI_EditText::set_int_val( int new_val )
  852. {
  853.   if ( has_limits == GLUI_LIMIT_CLAMP ) {
  854.     /*** Clamp the new value to the existing limits ***/
  855.     CLAMP( new_val, int_low, int_high );
  856.   }
  857.   else if ( has_limits == GLUI_LIMIT_WRAP ) {
  858.     /*** Clamp the value cyclically to the limits - that is, if the
  859.       value exceeds the max, set it the the minimum, and conversely ***/
  860.     if ( new_val < int_low )
  861.       new_val = int_high;
  862.     if ( new_val > int_high )
  863.       new_val = int_low;
  864.   }
  865.   int_val   = new_val;
  866.   float_val = (float) new_val;   /* We mirror the value as a float, too */
  867.   set_numeric_text();
  868. }
  869. /********************************* GLUI_EditText::set_float_limits() *********/
  870. void GLUI_EditText::set_float_limits( float low, float high, int limit_type )
  871. {
  872.   has_limits  = limit_type;
  873.   float_low   = low;
  874.   float_high  = high;
  875.   
  876.   if ( NOT IN_BOUNDS( float_val, float_low, float_high ))
  877.     set_float_val( float_low );
  878.   int_low     = (int) float_low;
  879.   int_high    = (int) float_high;
  880. }
  881. /*********************************** GLUI_EditText::set_int_limits() *********/
  882. void   GLUI_EditText::set_int_limits( int low, int high, int limit_type )
  883. {
  884.   has_limits  = limit_type;
  885.   int_low     = low;
  886.   int_high    = high;
  887.   if ( NOT IN_BOUNDS( int_val, int_low, int_high ))
  888.     set_int_val( int_low );
  889.   float_low   = (float) int_low;
  890.   float_high  = (float) int_high;
  891. }
  892. /************************************ GLUI_EditText::set_numeric_text() ******/
  893. void    GLUI_EditText::set_numeric_text( void )
  894. {
  895.   char buf_num[200];
  896.   int  i, text_len;
  897.   if ( data_type == GLUI_EDITTEXT_FLOAT ) {
  898.     sprintf( buf_num, "%#g", float_val );
  899.     num_periods = 0;
  900.     text_len = (int) strlen(buf_num);
  901.     for ( i=0; i<text_len; i++ )
  902.       if ( buf_num[i] == '.' )
  903.         num_periods++;
  904.     /* Now remove trailing zeros */
  905.     if ( num_periods > 0 ) {
  906.       text_len = (int) strlen(buf_num);
  907.       for ( i=text_len-1; i>0; i-- ) {
  908.         if ( buf_num[i] == '0' AND buf_num[i-1] != '.' )
  909.           buf_num[i] = '';
  910.         else 
  911.           break;
  912.       }
  913.     }
  914.     set_text( buf_num );
  915.   }
  916.   else {
  917.     sprintf( buf_num, "%d", int_val );
  918.     set_text( buf_num );
  919.   }
  920.     
  921. }
  922. /*************************************** GLUI_EditText::dump() **************/
  923. void   GLUI_EditText::dump( FILE *out, const char *name )
  924. {
  925.   fprintf( out, 
  926.            "%s (edittext@%p):  ins_pt:%d  subs:%d/%d  sel:%d/%d   len:%dn",
  927.            name, this, 
  928.            insertion_pt,
  929.            substring_start,
  930.            substring_end,
  931.            sel_start,
  932.            sel_end,
  933.            (int) text.length());
  934. }
  935. /**************************************** GLUI_EditText::mouse_over() ********/
  936. int    GLUI_EditText::mouse_over( int state, int x, int y )
  937. {
  938.   if ( state ) {
  939.     /*  curr_cursor = GLUT_CURSOR_TEXT;              */
  940.     glutSetCursor( GLUT_CURSOR_TEXT );
  941.   }
  942.   else {
  943.     /*    printf( "OUTn" );              */
  944.     glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
  945.   }
  946.   return true;
  947. }