1 /****************************************************************************
2 
3   GLUI User Interface Toolkit
4   ---------------------------
5 
6      glui_edittext.cpp - GLUI_EditText control class
7 
8 
9           --------------------------------------------------
10 
11   Copyright (c) 1998 Paul Rademacher
12 
13   WWW:    http://sourceforge.net/projects/glui/
14   Forums: http://sourceforge.net/forum/?group_id=92496
15 
16   This software is provided 'as-is', without any express or implied
17   warranty. In no event will the authors be held liable for any damages
18   arising from the use of this software.
19 
20   Permission is granted to anyone to use this software for any purpose,
21   including commercial applications, and to alter it and redistribute it
22   freely, subject to the following restrictions:
23 
24   1. The origin of this software must not be misrepresented; you must not
25   claim that you wrote the original software. If you use this software
26   in a product, an acknowledgment in the product documentation would be
27   appreciated but is not required.
28   2. Altered source versions must be plainly marked as such, and must not be
29   misrepresented as being the original software.
30   3. This notice may not be removed or altered from any source distribution.
31 
32 *****************************************************************************/
33 
34 #include "glui_internal_control.h"
35 #include <cassert>
36 
37 /****************************** GLUI_EditText::GLUI_EditText() **********/
38 
39 GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
40                              int data_type, void *live_var,
41                              int id, GLUI_CB callback )
42 {
43   if (data_type == GLUI_EDITTEXT_TEXT) {
44     live_type = GLUI_LIVE_TEXT;
45   }
46   else if (data_type == GLUI_EDITTEXT_STRING) {
47    data_type = GLUI_EDITTEXT_TEXT;  // EDITTEXT_STRING doesn't really exist.
48                                      // Except as a signal to make a string.
49                                      // It's a backwards-compat hack.
50    live_type = GLUI_LIVE_STRING;
51   }
52   else if (data_type == GLUI_EDITTEXT_INT) {
53     live_type = GLUI_LIVE_INT;
54   }
55   else if (data_type == GLUI_EDITTEXT_FLOAT) {
56     live_type = GLUI_LIVE_FLOAT;
57   }
58   common_construct( parent, name, data_type, live_type, live_var, id, callback );
59 }
60 
61 /****************************** GLUI_EditText::GLUI_EditText() **********/
62 
63 GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
64                               int text_type, int id, GLUI_CB callback )
65 {
66   common_construct( parent, name, text_type, GLUI_LIVE_NONE, 0, id, callback);
67 }
68 
69 /****************************** GLUI_EditText::GLUI_EditText() **********/
70 
71 GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
72                               int *live_var,
73                               int id, GLUI_CB callback )
74 {
75   common_construct( parent, name, GLUI_EDITTEXT_INT, GLUI_LIVE_INT, live_var, id, callback);
76 }
77 
78 /****************************** GLUI_EditText::GLUI_EditText() **********/
79 
80 GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
81                               float *live_var,
82                               int id, GLUI_CB callback )
83 {
84   common_construct( parent, name, GLUI_EDITTEXT_FLOAT, GLUI_LIVE_FLOAT, live_var, id, callback);
85 }
86 
87 /****************************** GLUI_EditText::GLUI_EditText() **********/
88 
89 GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
90                               char *live_var,
91                               int id, GLUI_CB callback )
92 {
93   common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_TEXT, live_var, id, callback);
94 }
95 
96 /****************************** GLUI_EditText::GLUI_EditText() **********/
97 
98 GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
99                               std::string &live_var,
100                               int id, GLUI_CB callback )
101 {
102   common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_STRING, &live_var, id, callback);
103 }
104 
105 /****************************** GLUI_EditText::common_construct() **********/
106 
107 void GLUI_EditText::common_construct( GLUI_Node *parent, const char *name,
108                                       int data_t, int live_t, void *data, int id,
109                                       GLUI_CB cb )
110 {
111   common_init();
112   set_name( name );
113 
114   live_type   = live_t;
115   data_type   = data_t;
116   ptr_val     = data;
117   user_id     = id;
118   callback    = cb;
119 
120 
121   if ( live_type == GLUI_LIVE_INT) {
122     if ( data == NULL )
123       set_int_val(int_val);   /** Set to some default, in case of no live var **/
124   }
125   else if ( live_type == GLUI_LIVE_FLOAT ) {
126     num_periods = 1;
127     if ( data == NULL )
128       set_float_val(float_val);   /** Set to some default, in case of no live var **/
129   }
130 
131   parent->add_control( this );
132 
133   init_live();
134 }
135 
136 /****************************** GLUI_EditText::mouse_down_handler() **********/
137 
138 int    GLUI_EditText::mouse_down_handler( int local_x, int local_y )
139 {
140   int tmp_insertion_pt;
141 
142   if ( debug )    dump( stdout, "-> MOUSE DOWN" );
143 
144   tmp_insertion_pt = find_insertion_pt( local_x, local_y );
145   if ( tmp_insertion_pt == -1 ) {
146     if ( glui )
147       glui->deactivate_current_control(  );
148     return false;
149   }
150 
151   insertion_pt = tmp_insertion_pt;
152 
153   sel_start = sel_end = insertion_pt;
154 
155   if ( can_draw())
156     update_and_draw_text();
157 
158   if ( debug )    dump( stdout, "<- MOUSE UP" );
159 
160   return true;
161 }
162 
163 
164 /******************************** GLUI_EditText::mouse_up_handler() **********/
165 
166 int    GLUI_EditText::mouse_up_handler( int local_x, int local_y, bool inside )
167 {
168   return false;
169 }
170 
171 
172 /***************************** GLUI_EditText::mouse_held_down_handler() ******/
173 
174 int    GLUI_EditText::mouse_held_down_handler( int local_x, int local_y,
175 					       bool new_inside)
176 {
177   int tmp_pt;
h225rassrt_packet(void * phs,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * phi)178 
179   if ( NOT new_inside )
180     return false;
181 
182   if ( debug )    dump( stdout, "-> HELD DOWN" );
183 
184   tmp_pt = find_insertion_pt( local_x, local_y );
185 
186   if ( tmp_pt == -1 AND sel_end != 0 ) {    /* moved mouse past left edge */
187     special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT );
188   }
189   else if ( tmp_pt == substring_end+1 AND sel_end != (int) text.length()) {
190     /* moved mouse past right edge */
191     special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT );
192   }
193   else if ( tmp_pt != -1 AND tmp_pt != sel_end ) {
194     sel_end = insertion_pt = tmp_pt;
195 
196     update_and_draw_text();
197   }
198 
199   if ( debug )
200     dump( stdout, "<- HELD DOWN" );
201 
202   return false;
203 }
204 
205 
206 /****************************** GLUI_EditText::key_handler() **********/
207 
208 int    GLUI_EditText::key_handler( unsigned char key,int modifiers )
209 {
210   int i, regular_key;
211   /* int has_selection;              */
212 
213   if ( NOT glui )
214     return false;
215 
216   if ( debug )
217     dump( stdout, "-> KEY HANDLER" );
218 
219   regular_key = false;
220   bool ctrl_down = (modifiers & GLUT_ACTIVE_CTRL)!=0;
221   /*  has_selection = (sel_start != sel_end);              */
222 
223   if ( key == CTRL('m') ) {           /* RETURN */
224     /*    glui->deactivate_current_control();              */
225     deactivate();  /** Force callbacks, etc **/
226     activate(GLUI_ACTIVATE_TAB);     /** Reselect all text **/
227     redraw();
228     return true;
229   }
230   else if ( key  == CTRL('[')) {         /* ESCAPE */
231     glui->deactivate_current_control();
232     return true;
233   }
234   else if ( (key == 127 AND !ctrl_down) OR  /* FORWARD DELETE */
235             ( key == CTRL('d') AND modifiers == GLUT_ACTIVE_CTRL) )
236   {
237     if ( sel_start == sel_end ) {   /* no selection */
238       if ( insertion_pt < (int)text.length() ) {
239         /*** See if we're deleting a period in a float data-type box ***/
240         if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt]=='.' )
241           num_periods--;
242 
243         /*** Shift over string first ***/
244         text.erase(insertion_pt,1);
245       }
h225ras_call_equal(gconstpointer k1,gconstpointer k2)246     }
247     else {                         /* There is a selection */
248       clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
249       insertion_pt = MIN(sel_start,sel_end);
250       sel_start = sel_end = insertion_pt;
251     }
252   }
253   else if ( ((key == 127) AND ctrl_down) OR   // Delete word forward
254             ((key == 'd') AND (modifiers == GLUT_ACTIVE_ALT)) )
255   {
h225ras_call_hash(gconstpointer k)256     if ( sel_start == sel_end ) {   /* no selection */
257       sel_start = insertion_pt;
258       sel_end = find_word_break( insertion_pt, +1 );
259     }
260 
261     clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
262     insertion_pt = MIN(sel_start,sel_end);
263     sel_start = sel_end = insertion_pt;
find_h225ras_call(h225ras_call_info_key * h225ras_call_key,int category)264   }
265   else if ( key == CTRL('h') ) {       /* BACKSPACE */
266     if ( sel_start == sel_end ) {   /* no selection */
267       if ( insertion_pt > 0 ) {
268         /*** See if we're deleting a period in a float data-type box ***/
269         if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt-1]=='.' )
270           num_periods--;
271 
272         /*** Shift over string first ***/
273         insertion_pt--;
274         text.erase(insertion_pt,1);
275       }
276     }
277     else {                         /* There is a selection */
278       clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
279       insertion_pt = MIN(sel_start,sel_end);
280       sel_start = sel_end = insertion_pt;
281     }
282   }
283   else if ( modifiers == GLUT_ACTIVE_CTRL )  /* CTRL ONLY */
284   {
285     /* Ctrl-key bindings */
286     if ( key == CTRL('a') ) {
287       return special_handler( GLUT_KEY_HOME, 0 );
288     }
289     else if ( key == CTRL('e') ) {
290       return special_handler( GLUT_KEY_END, 0 );
291     }
292     else if ( key == CTRL('b') ) {
293       return special_handler( GLUT_KEY_LEFT, 0 );
294     }
295     else if ( key == CTRL('f') ) {
296       return special_handler( GLUT_KEY_RIGHT, 0 );
297     }
298     else if ( key == CTRL('p') ) {
append_h225ras_call(h225ras_call_t * prev_call,packet_info * pinfo,e_guid_t * guid,int category _U_)299       return special_handler( GLUT_KEY_UP, 0 );
300     }
301     else if ( key == CTRL('n') ) {
302       return special_handler( GLUT_KEY_DOWN, 0 );
303     }
304     else if ( key == CTRL('u') ) { /* ERASE LINE */
305       insertion_pt = 0;
306       text.erase(0,text.length());
307       sel_start = sel_end = 0;
308     }
309     else if ( key == CTRL('k') ) { /* KILL TO END OF LINE */
310       sel_start = sel_end = insertion_pt;
311       text.erase(insertion_pt,GLUI_String::npos);
312     }
313   }
314   else if ( modifiers == GLUT_ACTIVE_ALT ) /* ALT ONLY */
315   {
316     if ( key == 'b' ) { // Backward word
317       return special_handler ( GLUT_KEY_LEFT, GLUT_ACTIVE_CTRL );
318     }
319     if ( key == 'f' ) { // Forward word
320       return special_handler ( GLUT_KEY_RIGHT, GLUT_ACTIVE_CTRL );
321     }
h225_frame_end(void)322   }
323   else if ( (modifiers & GLUT_ACTIVE_CTRL) OR
324             (modifiers & GLUT_ACTIVE_ALT) )
325   {
326     /** ignore other keys with modifiers */
327     return true;
328   }
329   else { /* Regular key */
dissect_h225_H323UserInformation(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)330     regular_key = true;
331 
332     /** Check if we only accept numbers **/
333     if (data_type == GLUI_EDITTEXT_FLOAT ) {
334       if ( (key < '0' OR key > '9') AND key != '.' AND key != '-' )
335         return true;
336 
337       if ( key == '-' ) { /* User typed a '-' */
338 
339         /* If user has first character selected, then '-' is allowed */
340         if ( NOT ( MIN(sel_start,sel_end) == 0 AND
341                    MAX(sel_start,sel_end) > 0 ) ) {
342 
343           /* User does not have 1st char selected */
344           if (insertion_pt != 0 OR text[0] == '-' ) {
345             return true; /* Can only place negative at beginning of text,
346                             and only one of them */
347           }
348         }
349       }
350 
351       if ( key == '.' ) {
352         /*printf( "PERIOD: %d\n", num_periods );              */
353 
354         if ( num_periods > 0 ) {
355           /** We're trying to type a period, but the text already contains
356           a period.  Check whether the period is contained within
357           is current selection (thus it will be safely replaced) **/
358 
359           int period_found = false;
360           if ( sel_start != sel_end ) {
361             for( i=MIN(sel_end,sel_start); i<MAX(sel_start,sel_end); i++ ) {
362               /*  printf( "%c ", text[i] );              */
363               if ( text[i] == '.' ) {
364                 period_found = true;
365                 break;
366               }
dissect_h225_h225_RasMessage(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)367             }
368           }
369 
370           /* printf( "found: %d    num: %d\n", period_found, num_periods );              */
371 
372           if ( NOT period_found )
373             return true;
374         }
375       }
376     }
377     else if (data_type == GLUI_EDITTEXT_INT)
378     {
379       if ( (key < '0' OR key > '9') AND key != '-' )
380         return true;
381 
382       if ( key == '-' ) { /* User typed a '-' */
383 
384         /* If user has first character selected, then '-' is allowed */
385         if ( NOT ( MIN(sel_start,sel_end) == 0 AND
386           MAX(sel_start,sel_end) > 0 ) ) {
387 
388             /* User does not have 1st char selected */
389             if (insertion_pt != 0 OR text[0] == '-' ) {
390               return true; /* Can only place negative at beginning of text,
391                            and only one of them */
392             }
393           }
394       }
395     }
396 
397     /** This is just to get rid of warnings - the flag regular_key is
398       set if the key was not a backspace, return, whatever.  But I
399       believe if we're here, we know it was a regular key anyway */
400     if ( regular_key ) {
401     }
402 
403     /**** If there's a current selection, erase it ******/
404     if ( sel_start != sel_end ) {
405       clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
406       insertion_pt = MIN(sel_start,sel_end);
407       sel_start = sel_end = insertion_pt;
408     }
409 
410     /******** We insert the character into the string ***/
411 
412     text.insert(insertion_pt,1,key);
413 
414     /******** Move the insertion point and substring_end one over ******/
415     insertion_pt++;
416     substring_end++;
417 
418     sel_start = sel_end = insertion_pt;
419   }
420 
421   /******** Now redraw text ***********/
422   /* Hack to prevent text box from being cleared first **/
423   /**  int substring_change =  update_substring_bounds();
424   draw_text_only =
425   (NOT substring_change AND NOT has_selection AND regular_key );
426   */
427 
428   draw_text_only = false;  /** Well, hack is not yet working **/
429   update_and_draw_text();
430   draw_text_only = false;
431 
432 
433   if ( debug )
434     dump( stdout, "<- KEY HANDLER" );
435 
436   /*** Now look to see if this string has a period ***/
437   num_periods = 0;
438   for( i=0; i<(int)text.length(); i++ )
439     if ( text[i] == '.' )
440       num_periods++;
441 
442   return true;
443 }
444 
445 
446 /****************************** GLUI_EditText::activate() **********/
447 
448 void    GLUI_EditText::activate( int how )
449 {
h225_stat_init(stat_tap_table_ui * new_stat)450   if ( debug )
451     dump( stdout, "-> ACTIVATE" );
452 
453   active = true;
454 
455   if ( how == GLUI_ACTIVATE_MOUSE )
456     return;  /* Don't select everything if activated with mouse */
457 
458   orig_text = text;
459 
460   sel_start    = 0;
461   sel_end      = (int)text.length();
462   insertion_pt = 0;
463 
464   if ( debug )
465     dump( stdout, "<- ACTIVATE" );
466 }
467 
468 
469 /****************************** GLUI_EditText::deactivate() **********/
470 
471 void    GLUI_EditText::deactivate( void )
472 {
473   int    new_int_val;
474   float  new_float_val;
475 
476   active = false;
477 
478   if ( NOT glui )
479     return;
480 
481   if ( debug )
482     dump( stdout, "-> DISACTIVATE" );
483 
484   sel_start = sel_end = insertion_pt = -1;
485 
486   /***** Retrieve the current value from the text *****/
487   /***** The live variable will be updated by set_text() ****/
488   if ( data_type == GLUI_EDITTEXT_FLOAT ) {
489     if ( text.length() == 0 ) /* zero-length string - make it "0.0" */
490       text = "0.0";
491 
492     new_float_val = atof( text.c_str() );
493 
494     set_float_val( new_float_val );
495   }
496   else if ( data_type == GLUI_EDITTEXT_INT ) {
497     if ( text.length() == 0 ) /* zero-length string - make it "0" */
498       text = "0";
499 
500     new_int_val = atoi( text.c_str() );
501 
502     set_int_val( new_int_val );
503   }
504   else
505     if ( data_type == GLUI_EDITTEXT_TEXT ) {
506       set_text(text); /* This will force callbacks and gfx refresh */
507     }
508 
509   update_substring_bounds();
510 
511   /******** redraw text without insertion point ***********/
512   redraw();
513 
514   /***** Now do callbacks if value changed ******/
515   if ( orig_text != text ) {
516     this->execute_callback();
517 
518     if ( 0 ) {
519       /* THE CODE BELOW IS FROM WHEN SPINNER ALSO MAINTAINED CALLBACKS    */
520       if ( spinner == NULL ) {   /** Are we independent of a spinner?  **/
521         if ( callback ) {
522           callback( this );
523         }
524       }
525       else {                      /* We're attached to a spinner */
526         spinner->do_callbacks();  /* Let the spinner do the callback stuff */
527       }
528     }
529   }
530 
531   if ( debug )
532     dump( stdout, "<- DISACTIVATE" );
533 }
534 
535 /****************************** GLUI_EditText::draw() **********/
536 
537 void    GLUI_EditText::draw( int x, int y )
538 {
539   GLUI_DRAWINGSENTINAL_IDIOM
540   int name_x;
541 
542   name_x = MAX(text_x_offset - string_width(this->name) - 3,0);
543   draw_name( name_x , 13);
544 
545   glBegin( GL_LINES );
546   glColor3f( .5, .5, .5 );
547   glVertex2i( text_x_offset, 0 );     glVertex2i( w, 0 );
548   glVertex2i( text_x_offset, 0 );     glVertex2i( text_x_offset, h );
549 
550   glColor3f( 1., 1., 1. );
551   glVertex2i( text_x_offset, h );     glVertex2i( w, h );
552   glVertex2i( w, h );                 glVertex2i( w, 0 );
553 
554   if ( enabled )
555     glColor3f( 0., 0., 0. );
556   else
557     glColor3f( .25, .25, .25 );
558   glVertex2i( text_x_offset+1, 1 );     glVertex2i( w-1, 1 );
559   glVertex2i( text_x_offset+1, 1 );     glVertex2i( text_x_offset+1, h-1 );
560 
561   glColor3f( .75, .75, .75 );
562   glVertex2i( text_x_offset+1, h-1 );     glVertex2i( w-1, h-1 );
563   glVertex2i( w-1, h-1 );                 glVertex2i( w-1, 1 );
564   glEnd();
565 
566   /** Find where to draw the text **/
567   update_substring_bounds();
568   draw_text(0,0);
569 
570   draw_insertion_pt();
571 }
572 
573 
574 
575 /************************** GLUI_EditText::update_substring_bounds() *********/
576 
577 int    GLUI_EditText::update_substring_bounds( void )
578 {
579   int box_width;
580   int text_len = (int)text.length();
581   int old_start, old_end;
582 
583   old_start = substring_start;
584   old_end = substring_end;
585 
586   /*** Calculate the width of the usable area of the edit box ***/
587   box_width = MAX( this->w - this->text_x_offset
588 		   - 4     /*  2 * the two-line box border */
589 		   - 2 * GLUI_EDITTEXT_BOXINNERMARGINX, 0 );
590 
591   CLAMP( substring_end, 0, MAX(text_len-1,0) );
592   CLAMP( substring_start, 0, MAX(text_len-1,0) );
593 
594   if ( debug )    dump( stdout, "-> UPDATE SS" );
595 
596   if ( insertion_pt >= 0 AND
597        insertion_pt < substring_start ) {   /* cursor moved left */
598     substring_start = insertion_pt;
599 
600     while ( substring_width( substring_start, substring_end ) > box_width )
601       substring_end--;
602   }
603   else if ( insertion_pt > substring_end ) {  /* cursor moved right */
604     substring_end = insertion_pt-1;
605 
606     while ( substring_width( substring_start, substring_end ) > box_width )
607       substring_start++;
608   }
609   else {   /* cursor is within old substring bounds */
610     if ( last_insertion_pt > insertion_pt ) {  /* cursor moved left */
611     }
612     else {
613       while ( substring_width( substring_start, substring_end ) > box_width )
614 	substring_end--;
615 
616       while(substring_end < text_len-1
617             AND substring_width( substring_start, substring_end ) <= box_width)
618       	substring_end++;
619     }
620   }
621 
622   while ( substring_width( substring_start, substring_end ) > box_width )
623     substring_end--;
624 
625   last_insertion_pt = insertion_pt;
626 
627   /*** No selection if not enabled ***/
628   if ( NOT enabled ) {
629     sel_start = sel_end = 0;
630   }
631 
632   if ( debug )    dump( stdout, "<- UPDATE SS" );
633 
634   if ( substring_start == old_start AND substring_end == old_end )
635     return false;  /*** bounds did not change ***/
636   else
637     return true;   /*** bounds did change ***/
638 }
639 
640 
641 /********************************* GLUI_EditText::update_x_offsets() *********/
642 
643 void    GLUI_EditText::update_x_offsets( void )
644 {
645 }
646 
647 
648 /********************************* GLUI_EditText::draw_text() ****************/
649 
650 void    GLUI_EditText::draw_text( int x, int y )
651 {
652   GLUI_DRAWINGSENTINAL_IDIOM
653   int text_x, i, sel_lo, sel_hi;
654 
655   if ( debug )    dump( stdout, "-> DRAW_TEXT" );
656 
657   if ( NOT draw_text_only ) {
658     if ( enabled )
659       glColor3f( 1., 1., 1. );
660     else
661       set_to_bkgd_color();
662     glDisable( GL_CULL_FACE );
663     glBegin( GL_QUADS );
664     glVertex2i( text_x_offset+2, 2 );     glVertex2i( w-2, 2 );
665     glVertex2i( w-2, h-2 );               glVertex2i( text_x_offset+2, h-2 );
666     glEnd();
667   }
668 
669   /** Find where to draw the text **/
670 
671   text_x = text_x_offset + 2 + GLUI_EDITTEXT_BOXINNERMARGINX;
672 
673   /*printf( "text_x: %d      substr_width: %d     start/end: %d/%d\n",
674     text_x,     substring_width( substring_start, substring_end ),
675     substring_start, substring_end );
676     */
677   /** Find lower and upper selection bounds **/
h225_stat_packet(void * tapdata,packet_info * pinfo _U_,epan_dissect_t * edt _U_,const void * hpi_ptr)678   sel_lo = MIN(sel_start, sel_end );
679   sel_hi = MAX(sel_start, sel_end );
680 
681   int sel_x_start, sel_x_end, delta;
682 
683   /** Draw selection area dark **/
684   if ( sel_start != sel_end ) {
685     sel_x_start = text_x;
686     sel_x_end   = text_x;
687     for( i=substring_start; i<=substring_end; i++ ) {
688       delta = char_width( text[i] );
689 
690       if ( i < sel_lo ) {
691 	sel_x_start += delta;
692 	sel_x_end   += delta;
693       }
694       else if ( i < sel_hi ) {
695 	sel_x_end   += delta;
696       }
697     }
698 
699     glColor3f( 0.0f, 0.0f, .6f );
700     glBegin( GL_QUADS );
701     glVertex2i( sel_x_start, 2 );    glVertex2i( sel_x_end, 2 );
702     glVertex2i( sel_x_end, h-2 );    glVertex2i( sel_x_start, h-2 );
703     glEnd();
704   }
705 
706 
707   if ( sel_start == sel_end ) {   /* No current selection */
708     if ( enabled )
709       glColor3b( 0, 0, 0 );
710     else
711       glColor3b( 32, 32, 32 );
712 
713     glRasterPos2i( text_x, 13);
714     for( i=substring_start; i<=substring_end; i++ ) {
715       glutBitmapCharacter( get_font(), this->text[i] );
716     }
717   }
718   else {                          /* There is a selection */
719     int x = text_x;
720     for( i=substring_start; i<=substring_end; i++ ) {
721       if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { /* This character is selected */
722 	glColor3f( 1., 1., 1. );
723 	glRasterPos2i( x, 13);
724 	glutBitmapCharacter( get_font(), this->text[i] );
725       }
726       else {
727 	glColor3f( 0., 0., 0. );
728 	glRasterPos2i( x, 13);
729 	glutBitmapCharacter( get_font(), this->text[i] );
730       }
731 
732       x += char_width( text[i] );
733     }
734   }
735 
736   if ( debug )    dump( stdout, "<- DRAW_TEXT" );
737 }
738 
739 
740 /******************************** GLUI_EditText::find_insertion_pt() *********/
741 /* This function returns the character numer *before which* the insertion    */
742 /* point goes                                                                */
743 
744 int  GLUI_EditText::find_insertion_pt( int x, int y )
745 {
746   int curr_x, i;
747 
748   /*** See if we clicked outside box ***/
749   if ( x < this->x_abs + text_x_offset )
750     return -1;
751 
752   /* We move from right to left, looking to see if the mouse was clicked
753      to the right of the ith character */
754 
755   curr_x = this->x_abs + text_x_offset
756     + substring_width( substring_start, substring_end )
757     + 2                             /* The edittext box has a 2-pixel margin */
758     + GLUI_EDITTEXT_BOXINNERMARGINX;   /** plus this many pixels blank space
759 					 between the text and the box       **/
760 
761   /*** See if we clicked in an empty box ***/
762   if ( (int) text.length() == 0 )
763     return 0;
764 
765   /** find mouse click in text **/
766   for( i=substring_end; i>=substring_start; i-- ) {
767     curr_x -= char_width( text[i] );
768 
769     if ( x > curr_x ) {
770       /*      printf( "-> %d\n", i );              */
771 
772       return i+1;
773     }
774   }
775 
776   return 0;
777 
778   /* Well, the mouse wasn't after any of the characters...see if it's
779      before the beginning of the substring */
780   if ( 0 ) {
781     if ( x > (x_abs + text_x_offset + 2 ) )
782       return substring_start;
783 
h225_stat_reset(stat_tap_table * table)784     return -1; /* Nothing found */
785   }
786 }
787 
788 
789 /******************************** GLUI_EditText::draw_insertion_pt() *********/
790 
791 void     GLUI_EditText::draw_insertion_pt( void )
792 {
793   int curr_x, i;
794 
795   if ( NOT can_draw() )
796     return;
797 
proto_register_h225(void)798   /*** Don't draw insertion pt if control is disabled ***/
799   if ( NOT enabled )
800     return;
801 
802   if ( debug )    dump( stdout, "-> DRAW_INS_PT" );
803 
804   if ( sel_start != sel_end OR insertion_pt < 0 ) {
805     return;  /* Don't draw insertion point if there is a current selection */
806   }
807 
808   /*    printf( "insertion pt: %d\n", insertion_pt );              */
809 
810   curr_x = this->x_abs + text_x_offset
811     + substring_width( substring_start, substring_end )
812     + 2                             /* The edittext box has a 2-pixel margin */
813     + GLUI_EDITTEXT_BOXINNERMARGINX;   /** plus this many pixels blank space
814 					 between the text and the box       **/
815 
816   for( i=substring_end; i>=insertion_pt; i-- ) {
817     curr_x -= char_width( text[i] );
818   }
819 
820   glColor3f( 0.0, 0.0, 0.0 );
821   glBegin( GL_LINE_LOOP );
822   /***
823     glVertex2i( curr_x, y_abs + 4 );
824     glVertex2i( curr_x, y_abs + 4 );
825     glVertex2i( curr_x, y_abs + h - 3 );
826     glVertex2i( curr_x, y_abs + h - 3 );
827     ***/
828   curr_x -= x_abs;
829   glVertex2i( curr_x, 0 + 4 );
830   glVertex2i( curr_x, 0 + 4 );
831   glVertex2i( curr_x, 0 + h - 3 );
832   glVertex2i( curr_x, 0 + h - 3 );
833   glEnd();
834 
835   if ( debug )    dump( stdout, "-> DRAW_INS_PT" );
836 }
837 
838 
839 
840 /******************************** GLUI_EditText::substring_width() *********/
841 
842 int  GLUI_EditText::substring_width( int start, int end )
843 {
844   int i, width;
845 
846   width = 0;
847 
848   for( i=start; i<=end; i++ )
849     width += char_width( text[i] );
850 
851   return width;
852 }
853 
854 
855 /***************************** GLUI_EditText::update_and_draw_text() ********/
856 
857 void   GLUI_EditText::update_and_draw_text( void )
858 {
859   if ( NOT can_draw() )
860     return;
861 
862   update_substring_bounds();
863   /*  printf( "ss: %d/%d\n", substring_start, substring_end );                  */
864 
865   redraw();
866 }
867 
868 
869 /********************************* GLUI_EditText::special_handler() **********/
870 
871 int    GLUI_EditText::special_handler( int key,int modifiers )
872 {
873   if ( NOT glui )
874     return false;
875 
876   if ( debug )
877     printf( "SPECIAL:%d - mod:%d   subs:%d/%d  ins:%d  sel:%d/%d\n",
878 	    key, modifiers, substring_start, substring_end,insertion_pt,
879 	    sel_start, sel_end );
880 
881   if ( key == GLUT_KEY_LEFT ) {
882     if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
883       insertion_pt = find_word_break( insertion_pt, -1 );
884     }
885     else {
886       insertion_pt--;
887     }
888   }
889   else if ( key == GLUT_KEY_RIGHT ) {
890     if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
891       insertion_pt = find_word_break( insertion_pt, +1 );
892     }
893     else {
894       insertion_pt++;
895     }
896   }
897   else if ( key == GLUT_KEY_HOME ) {
898     insertion_pt = 0;
899   }
900   else if ( key == GLUT_KEY_END ) {
901     insertion_pt = (int) text.length();
902   }
903 
904   /*** Update selection if shift key is down ***/
905   if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 )
906     sel_end = insertion_pt;
907   else
908     sel_start = sel_end = insertion_pt;
909 
910 
911   CLAMP( insertion_pt, 0, (int) text.length()); /* Make sure insertion_pt
912 						                                      is in bounds */
913   CLAMP( sel_start, 0, (int) text.length()); /* Make sure insertion_pt
914 						                                    is in bounds */
915   CLAMP( sel_end, 0, (int) text.length()); /* Make sure insertion_pt
916 					                                     is in bounds */
917 
proto_reg_handoff_h225(void)918   /******** Now redraw text ***********/
919   if ( can_draw())
920     update_and_draw_text();
921 
922   return true;
923 }
924 
925 
926 /****************************** GLUI_EditText::find_word_break() **********/
927 /* It looks either left or right (depending on value of 'direction'       */
928 /* for the beginning of the next 'word', where word are characters        */
929 /* separated by one of the following tokens:  " :-.,"                     */
930 /* If there is no next word in the specified direction, this returns      */
931 /* the beginning of 'text', or the very end.                              */
932 
933 int    GLUI_EditText::find_word_break( int start, int direction )
934 {
935   int    i, j;
936   char   *breaks = " :-.,";
937   int     num_break_chars = (int)strlen(breaks), text_len = (int)text.length();
938   int     new_pt;
939 
940   /** If we're moving left, we have to start two back, in case we're either
create_h225_packet_info(packet_info * pinfo)941   already at the beginning of a word, or on a separating token.
942   Otherwise, this function would just return the word we're already at **/
943   if ( direction == -1 ) {
944     start -= 2;
945   }
946 
947   /***** Iterate over text in the specified direction *****/
948   for ( i=start; i >= 0 AND i < text_len; i += direction ) {
949 
950     /** For each character in text, iterate over list of separating tokens **/
951     for( j=0; j<num_break_chars; j++ ) {
952       if ( text[i] == breaks[j] ) {
953 
954         /** character 'i' is a separating token, so we return i+1 **/
955         new_pt = i + 1;
956 
957         CLAMP( new_pt, 0, text_len );
958 
959         return new_pt;
960       }
961     }
962   }
963 
964   if ( direction > 0 )  /* Return the end of string */
965     return text_len;
966   else                  /* Return the beginning of the text */
967     return 0;
968 }
969 
970 
971 /********************************** GLUI_EditText::clear_substring() ********/
972 
973 void   GLUI_EditText::clear_substring( int start, int end )
974 {
975   int i;
976 
977   /*
978   printf( "clearing: %d-%d   '", start,end);
979   for(i=start;i<end;i++ )
980   putchar(text[i]);
ras_call_matching(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,h225_packet_info * pi)981   printf( "'\n" ); flushout;
982   */
983   /*** See if we're deleting a period in a float data-type box ***/
984   if ( data_type == GLUI_EDITTEXT_FLOAT ) {
985     for( i=start; i<end; i++ )
986       if ( text[i] == '.' )
987         num_periods = 0;
988   }
989 
990   text.erase(start,end-start);
991 }
992 
993 
994 
995 /************************************ GLUI_EditText::update_size() **********/
996 
997 void   GLUI_EditText::update_size( void )
998 {
999   int text_size, delta;
1000 
1001   if ( NOT glui )
1002     return;
1003 
1004   text_size = string_width( name );
1005 
1006   delta = 0;
1007   if ( text_x_offset < text_size +2 )
1008     delta = text_size+2-text_x_offset;
1009 
1010   text_x_offset += delta;
1011   /*  w += delta;              */
1012 
1013   if ( data_type == GLUI_EDITTEXT_TEXT OR
1014        data_type == GLUI_EDITTEXT_FLOAT) {
1015     if ( w < text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH )
1016       w = text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH;
1017   }
1018   else if ( data_type == GLUI_EDITTEXT_INT ) {
1019     if ( w < text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH )
1020       w = text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH;
1021   }
1022 }
1023 
1024 
1025 /****************************** GLUI_EditText::set_text() **********/
1026 
1027 void    GLUI_EditText::set_text( const char *new_text )
1028 {
1029   text=new_text;
1030   substring_start = 0;
1031   substring_end   = (int) text.length() - 1;
1032   insertion_pt    = -1;
1033   sel_start       = 0;
1034   sel_end         = 0;
1035 
1036   if ( can_draw() )
1037     update_and_draw_text();
1038 
1039   /** Update the spinner, if we have one **/
1040   if ( spinner ) {
1041     spinner->float_val = this->float_val;
1042     spinner->int_val   = this->int_val;
1043   }
1044 
1045   /*** Now update the live variable ***/
1046   output_live(true);
1047 }
1048 
1049 
1050 /******************************* GLUI_EditText::set_float_val() ************/
1051 
1052 void   GLUI_EditText::set_float_val( float new_val )
1053 {
1054   if ( has_limits == GLUI_LIMIT_CLAMP ) {
1055     /*** Clamp the new value to the existing limits ***/
1056 
1057     CLAMP( new_val, float_low, float_high );
1058   }
1059   else if ( has_limits == GLUI_LIMIT_WRAP ) {
1060     /*** Clamp the value cyclically to the limits - that is, if the
1061       value exceeds the max, set it the the minimum, and conversely ***/
1062 
1063     if ( new_val < float_low )
1064       new_val = float_high;
1065     if ( new_val > float_high )
1066       new_val = float_low;
1067   }
1068 
1069   float_val = new_val;
1070   int_val   = (int) new_val;  /* Mirror the value as an int, too */
1071 
1072   set_numeric_text();
1073 }
1074 
1075 
1076 /********************************** GLUI_EditText::set_int_val() ************/
1077 
1078 void   GLUI_EditText::set_int_val( int new_val )
1079 {
1080   if ( has_limits == GLUI_LIMIT_CLAMP ) {
1081     /*** Clamp the new value to the existing limits ***/
1082 
1083     CLAMP( new_val, int_low, int_high );
1084   }
1085   else if ( has_limits == GLUI_LIMIT_WRAP ) {
1086     /*** Clamp the value cyclically to the limits - that is, if the
1087       value exceeds the max, set it the the minimum, and conversely ***/
1088 
1089     if ( new_val < int_low )
1090       new_val = int_high;
1091     if ( new_val > int_high )
1092       new_val = int_low;
1093   }
1094 
1095   int_val   = new_val;
1096   float_val = (float) new_val;   /* We mirror the value as a float, too */
1097 
1098   set_numeric_text();
1099 }
1100 
1101 
1102 /********************************* GLUI_EditText::set_float_limits() *********/
1103 
1104 void GLUI_EditText::set_float_limits( float low, float high, int limit_type )
1105 {
1106   has_limits  = limit_type;
1107   float_low   = low;
1108   float_high  = high;
1109 
1110   if ( NOT IN_BOUNDS( float_val, float_low, float_high ))
1111     set_float_val( float_low );
1112 
1113   int_low     = (int) float_low;
1114   int_high    = (int) float_high;
1115 }
1116 
1117 
1118 /*********************************** GLUI_EditText::set_int_limits() *********/
1119 
1120 void   GLUI_EditText::set_int_limits( int low, int high, int limit_type )
1121 {
1122   has_limits  = limit_type;
1123   int_low     = low;
1124   int_high    = high;
1125 
1126   if ( NOT IN_BOUNDS( int_val, int_low, int_high ))
1127     set_int_val( int_low );
1128 
1129   float_low   = (float) int_low;
1130   float_high  = (float) int_high;
1131 }
1132 
1133 
1134 /************************************ GLUI_EditText::set_numeric_text() ******/
1135 
1136 void    GLUI_EditText::set_numeric_text( void )
1137 {
1138   char buf_num[200];
1139   int  i, text_len;
1140 
1141   if ( data_type == GLUI_EDITTEXT_FLOAT ) {
1142     sprintf( buf_num, "%#g", float_val );
1143 
1144     num_periods = 0;
1145     text_len = (int) strlen(buf_num);
1146     for ( i=0; i<text_len; i++ )
1147       if ( buf_num[i] == '.' )
1148         num_periods++;
1149 
1150     /* Now remove trailing zeros */
1151     if ( num_periods > 0 ) {
1152       text_len = (int) strlen(buf_num);
1153       for ( i=text_len-1; i>0; i-- ) {
1154         if ( buf_num[i] == '0' AND buf_num[i-1] != '.' )
1155           buf_num[i] = '\0';
1156         else
1157           break;
1158       }
1159     }
1160     set_text( buf_num );
1161   }
1162   else {
1163     sprintf( buf_num, "%d", int_val );
1164     set_text( buf_num );
1165   }
1166 
1167 }
1168 
1169 
1170 /*************************************** GLUI_EditText::dump() **************/
1171 
1172 void   GLUI_EditText::dump( FILE *out, const char *name )
1173 {
1174   fprintf( out,
1175            "%s (edittext@%p):  ins_pt:%d  subs:%d/%d  sel:%d/%d   len:%d\n",
1176            name, this,
1177            insertion_pt,
1178            substring_start,
1179            substring_end,
1180            sel_start,
1181            sel_end,
1182            (int) text.length());
1183 }
1184 
1185 
1186 /**************************************** GLUI_EditText::mouse_over() ********/
1187 
1188 int    GLUI_EditText::mouse_over( int state, int x, int y )
1189 {
1190   if ( state ) {
1191     /*  curr_cursor = GLUT_CURSOR_TEXT;              */
1192     glutSetCursor( GLUT_CURSOR_TEXT );
1193   }
1194   else {
1195     /*    printf( "OUT\n" );              */
1196     glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
1197   }
1198 
1199   return true;
1200 }
1201