1
/****************************************************************************
3
GLUI User Interface Toolkit
4
---------------------------
6
glui_edittext.cpp - GLUI_EditText control class
9
--------------------------------------------------
11
Copyright (c) 1998 Paul Rademacher
13
WWW: http://sourceforge.net/projects/glui/
14
Forums: http://sourceforge.net/forum/?group_id=92496
16
This library is free software; you can redistribute it and/or
17
modify it under the terms of the GNU Lesser General Public
18
License as published by the Free Software Foundation; either
19
version 2.1 of the License, or (at your option) any later version.
21
This library is distributed in the hope that it will be useful,
22
but WITHOUT ANY WARRANTY; without even the implied warranty of
23
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24
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
30
*****************************************************************************/
32
#include "glui_internal_control.h"
35
/****************************** GLUI_EditText::GLUI_EditText() **********/
37
GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
38
int data_type, void *live_var,
39
int id, GLUI_CB callback )
41
if (data_type == GLUI_EDITTEXT_TEXT) {
42
live_type = GLUI_LIVE_TEXT;
44
else if (data_type == GLUI_EDITTEXT_STRING) {
45
data_type = GLUI_EDITTEXT_TEXT; // EDITTEXT_STRING doesn't really exist.
46
// Except as a signal to make a string.
47
// It's a backwards-compat hack.
48
live_type = GLUI_LIVE_STRING;
50
else if (data_type == GLUI_EDITTEXT_INT) {
51
live_type = GLUI_LIVE_INT;
53
else if (data_type == GLUI_EDITTEXT_FLOAT) {
54
live_type = GLUI_LIVE_FLOAT;
56
common_construct( parent, name, data_type, live_type, live_var, id, callback );
59
/****************************** GLUI_EditText::GLUI_EditText() **********/
61
GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
62
int text_type, int id, GLUI_CB callback )
64
common_construct( parent, name, text_type, GLUI_LIVE_NONE, 0, id, callback);
67
/****************************** GLUI_EditText::GLUI_EditText() **********/
69
GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
71
int id, GLUI_CB callback )
73
common_construct( parent, name, GLUI_EDITTEXT_INT, GLUI_LIVE_INT, live_var, id, callback);
76
/****************************** GLUI_EditText::GLUI_EditText() **********/
78
GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
80
int id, GLUI_CB callback )
82
common_construct( parent, name, GLUI_EDITTEXT_FLOAT, GLUI_LIVE_FLOAT, live_var, id, callback);
85
/****************************** GLUI_EditText::GLUI_EditText() **********/
87
GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
89
int id, GLUI_CB callback )
91
common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_TEXT, live_var, id, callback);
94
/****************************** GLUI_EditText::GLUI_EditText() **********/
96
GLUI_EditText::GLUI_EditText( GLUI_Node *parent, const char *name,
97
std::string &live_var,
98
int id, GLUI_CB callback )
100
common_construct( parent, name, GLUI_EDITTEXT_TEXT, GLUI_LIVE_STRING, &live_var, id, callback);
103
/****************************** GLUI_EditText::common_construct() **********/
105
void GLUI_EditText::common_construct( GLUI_Node *parent, const char *name,
106
int data_t, int live_t, void *data, int id,
119
if ( live_type == GLUI_LIVE_INT) {
121
set_int_val(int_val); /** Set to some default, in case of no live var **/
123
else if ( live_type == GLUI_LIVE_FLOAT ) {
126
set_float_val(float_val); /** Set to some default, in case of no live var **/
129
parent->add_control( this );
134
/****************************** GLUI_EditText::mouse_down_handler() **********/
136
int GLUI_EditText::mouse_down_handler( int local_x, int local_y )
138
int tmp_insertion_pt;
140
if ( debug ) dump( stdout, "-> MOUSE DOWN" );
142
tmp_insertion_pt = find_insertion_pt( local_x, local_y );
143
if ( tmp_insertion_pt == -1 ) {
145
glui->deactivate_current_control( );
149
insertion_pt = tmp_insertion_pt;
151
sel_start = sel_end = insertion_pt;
154
update_and_draw_text();
156
if ( debug ) dump( stdout, "<- MOUSE UP" );
162
/******************************** GLUI_EditText::mouse_up_handler() **********/
164
int GLUI_EditText::mouse_up_handler( int local_x, int local_y, bool inside )
170
/***************************** GLUI_EditText::mouse_held_down_handler() ******/
172
int GLUI_EditText::mouse_held_down_handler( int local_x, int local_y,
177
if ( NOT new_inside )
180
if ( debug ) dump( stdout, "-> HELD DOWN" );
182
tmp_pt = find_insertion_pt( local_x, local_y );
184
if ( tmp_pt == -1 AND sel_end != 0 ) { /* moved mouse past left edge */
185
special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT );
187
else if ( tmp_pt == substring_end+1 AND sel_end != (int) text.length()) {
188
/* moved mouse past right edge */
189
special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT );
191
else if ( tmp_pt != -1 AND tmp_pt != sel_end ) {
192
sel_end = insertion_pt = tmp_pt;
194
update_and_draw_text();
198
dump( stdout, "<- HELD DOWN" );
204
/****************************** GLUI_EditText::key_handler() **********/
206
int GLUI_EditText::key_handler( unsigned char key,int modifiers )
209
/* int has_selection; */
215
dump( stdout, "-> KEY HANDLER" );
218
bool ctrl_down = (modifiers & GLUT_ACTIVE_CTRL)!=0;
219
/* has_selection = (sel_start != sel_end); */
221
if ( key == CTRL('m') ) { /* RETURN */
222
/* glui->deactivate_current_control(); */
223
deactivate(); /** Force callbacks, etc **/
224
activate(GLUI_ACTIVATE_TAB); /** Reselect all text **/
228
else if ( key == CTRL('[')) { /* ESCAPE */
229
glui->deactivate_current_control();
232
else if ( (key == 127 AND !ctrl_down) OR /* FORWARD DELETE */
233
( key == CTRL('d') AND modifiers == GLUT_ACTIVE_CTRL) )
235
if ( sel_start == sel_end ) { /* no selection */
236
if ( insertion_pt < (int)text.length() ) {
237
/*** See if we're deleting a period in a float data-type box ***/
238
if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt]=='.' )
241
/*** Shift over string first ***/
242
text.erase(insertion_pt,1);
245
else { /* There is a selection */
246
clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
247
insertion_pt = MIN(sel_start,sel_end);
248
sel_start = sel_end = insertion_pt;
251
else if ( ((key == 127) AND ctrl_down) OR // Delete word forward
252
((key == 'd') AND (modifiers == GLUT_ACTIVE_ALT)) )
254
if ( sel_start == sel_end ) { /* no selection */
255
sel_start = insertion_pt;
256
sel_end = find_word_break( insertion_pt, +1 );
259
clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
260
insertion_pt = MIN(sel_start,sel_end);
261
sel_start = sel_end = insertion_pt;
263
else if ( key == CTRL('h') ) { /* BACKSPACE */
264
if ( sel_start == sel_end ) { /* no selection */
265
if ( insertion_pt > 0 ) {
266
/*** See if we're deleting a period in a float data-type box ***/
267
if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt-1]=='.' )
270
/*** Shift over string first ***/
272
text.erase(insertion_pt,1);
275
else { /* There is a selection */
276
clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
277
insertion_pt = MIN(sel_start,sel_end);
278
sel_start = sel_end = insertion_pt;
281
else if ( modifiers == GLUT_ACTIVE_CTRL ) /* CTRL ONLY */
283
/* Ctrl-key bindings */
284
if ( key == CTRL('a') ) {
285
return special_handler( GLUT_KEY_HOME, 0 );
287
else if ( key == CTRL('e') ) {
288
return special_handler( GLUT_KEY_END, 0 );
290
else if ( key == CTRL('b') ) {
291
return special_handler( GLUT_KEY_LEFT, 0 );
293
else if ( key == CTRL('f') ) {
294
return special_handler( GLUT_KEY_RIGHT, 0 );
296
else if ( key == CTRL('p') ) {
297
return special_handler( GLUT_KEY_UP, 0 );
299
else if ( key == CTRL('n') ) {
300
return special_handler( GLUT_KEY_DOWN, 0 );
302
else if ( key == CTRL('u') ) { /* ERASE LINE */
304
text.erase(0,text.length());
305
sel_start = sel_end = 0;
307
else if ( key == CTRL('k') ) { /* KILL TO END OF LINE */
308
sel_start = sel_end = insertion_pt;
309
text.erase(insertion_pt,GLUI_String::npos);
312
else if ( modifiers == GLUT_ACTIVE_ALT ) /* ALT ONLY */
314
if ( key == 'b' ) { // Backward word
315
return special_handler ( GLUT_KEY_LEFT, GLUT_ACTIVE_CTRL );
317
if ( key == 'f' ) { // Forward word
318
return special_handler ( GLUT_KEY_RIGHT, GLUT_ACTIVE_CTRL );
321
else if ( (modifiers & GLUT_ACTIVE_CTRL) OR
322
(modifiers & GLUT_ACTIVE_ALT) )
324
/** ignore other keys with modifiers */
327
else { /* Regular key */
330
/** Check if we only accept numbers **/
331
if (data_type == GLUI_EDITTEXT_FLOAT ) {
332
if ( (key < '0' OR key > '9') AND key != '.' AND key != '-' )
335
if ( key == '-' ) { /* User typed a '-' */
337
/* If user has first character selected, then '-' is allowed */
338
if ( NOT ( MIN(sel_start,sel_end) == 0 AND
339
MAX(sel_start,sel_end) > 0 ) ) {
341
/* User does not have 1st char selected */
342
if (insertion_pt != 0 OR text[0] == '-' ) {
343
return true; /* Can only place negative at beginning of text,
344
and only one of them */
350
/*printf( "PERIOD: %d\n", num_periods ); */
352
if ( num_periods > 0 ) {
353
/** We're trying to type a period, but the text already contains
354
a period. Check whether the period is contained within
355
is current selection (thus it will be safely replaced) **/
357
int period_found = false;
358
if ( sel_start != sel_end ) {
359
for( i=MIN(sel_end,sel_start); i<MAX(sel_start,sel_end); i++ ) {
360
/* printf( "%c ", text[i] ); */
361
if ( text[i] == '.' ) {
368
/* printf( "found: %d num: %d\n", period_found, num_periods ); */
370
if ( NOT period_found )
375
else if (data_type == GLUI_EDITTEXT_INT)
377
if ( (key < '0' OR key > '9') AND key != '-' )
380
if ( key == '-' ) { /* User typed a '-' */
382
/* If user has first character selected, then '-' is allowed */
383
if ( NOT ( MIN(sel_start,sel_end) == 0 AND
384
MAX(sel_start,sel_end) > 0 ) ) {
386
/* User does not have 1st char selected */
387
if (insertion_pt != 0 OR text[0] == '-' ) {
388
return true; /* Can only place negative at beginning of text,
389
and only one of them */
395
/** This is just to get rid of warnings - the flag regular_key is
396
set if the key was not a backspace, return, whatever. But I
397
believe if we're here, we know it was a regular key anyway */
401
/**** If there's a current selection, erase it ******/
402
if ( sel_start != sel_end ) {
403
clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
404
insertion_pt = MIN(sel_start,sel_end);
405
sel_start = sel_end = insertion_pt;
408
/******** We insert the character into the string ***/
410
text.insert(insertion_pt,1,key);
412
/******** Move the insertion point and substring_end one over ******/
416
sel_start = sel_end = insertion_pt;
419
/******** Now redraw text ***********/
420
/* Hack to prevent text box from being cleared first **/
421
/** int substring_change = update_substring_bounds();
423
(NOT substring_change AND NOT has_selection AND regular_key );
426
draw_text_only = false; /** Well, hack is not yet working **/
427
update_and_draw_text();
428
draw_text_only = false;
432
dump( stdout, "<- KEY HANDLER" );
434
/*** Now look to see if this string has a period ***/
436
for( i=0; i<(int)text.length(); i++ )
437
if ( text[i] == '.' )
444
/****************************** GLUI_EditText::activate() **********/
446
void GLUI_EditText::activate( int how )
449
dump( stdout, "-> ACTIVATE" );
453
if ( how == GLUI_ACTIVATE_MOUSE )
454
return; /* Don't select everything if activated with mouse */
459
sel_end = (int)text.length();
463
dump( stdout, "<- ACTIVATE" );
467
/****************************** GLUI_EditText::deactivate() **********/
469
void GLUI_EditText::deactivate( void )
480
dump( stdout, "-> DISACTIVATE" );
482
sel_start = sel_end = insertion_pt = -1;
484
/***** Retrieve the current value from the text *****/
485
/***** The live variable will be updated by set_text() ****/
486
if ( data_type == GLUI_EDITTEXT_FLOAT ) {
487
if ( text.length() == 0 ) /* zero-length string - make it "0.0" */
490
new_float_val = atof( text.c_str() );
492
set_float_val( new_float_val );
494
else if ( data_type == GLUI_EDITTEXT_INT ) {
495
if ( text.length() == 0 ) /* zero-length string - make it "0" */
498
new_int_val = atoi( text.c_str() );
500
set_int_val( new_int_val );
503
if ( data_type == GLUI_EDITTEXT_TEXT ) {
504
set_text(text); /* This will force callbacks and gfx refresh */
507
update_substring_bounds();
509
/******** redraw text without insertion point ***********/
512
/***** Now do callbacks if value changed ******/
513
if ( orig_text != text ) {
514
this->execute_callback();
517
/* THE CODE BELOW IS FROM WHEN SPINNER ALSO MAINTAINED CALLBACKS */
518
if ( spinner == NULL ) { /** Are we independent of a spinner? **/
523
else { /* We're attached to a spinner */
524
spinner->do_callbacks(); /* Let the spinner do the callback stuff */
530
dump( stdout, "<- DISACTIVATE" );
533
/****************************** GLUI_EditText::draw() **********/
535
void GLUI_EditText::draw( int x, int y )
537
GLUI_DRAWINGSENTINAL_IDIOM
540
name_x = MAX(text_x_offset - string_width(this->name) - 3,0);
541
draw_name( name_x , 13);
544
glColor3f( .5, .5, .5 );
545
glVertex2i( text_x_offset, 0 ); glVertex2i( w, 0 );
546
glVertex2i( text_x_offset, 0 ); glVertex2i( text_x_offset, h );
548
glColor3f( 1., 1., 1. );
549
glVertex2i( text_x_offset, h ); glVertex2i( w, h );
550
glVertex2i( w, h ); glVertex2i( w, 0 );
553
glColor3f( 0., 0., 0. );
555
glColor3f( .25, .25, .25 );
556
glVertex2i( text_x_offset+1, 1 ); glVertex2i( w-1, 1 );
557
glVertex2i( text_x_offset+1, 1 ); glVertex2i( text_x_offset+1, h-1 );
559
glColor3f( .75, .75, .75 );
560
glVertex2i( text_x_offset+1, h-1 ); glVertex2i( w-1, h-1 );
561
glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 );
564
/** Find where to draw the text **/
565
update_substring_bounds();
573
/************************** GLUI_EditText::update_substring_bounds() *********/
575
int GLUI_EditText::update_substring_bounds( void )
578
int text_len = (int)text.length();
579
int old_start, old_end;
581
old_start = substring_start;
582
old_end = substring_end;
584
/*** Calculate the width of the usable area of the edit box ***/
585
box_width = MAX( this->w - this->text_x_offset
586
- 4 /* 2 * the two-line box border */
587
- 2 * GLUI_EDITTEXT_BOXINNERMARGINX, 0 );
589
CLAMP( substring_end, 0, MAX(text_len-1,0) );
590
CLAMP( substring_start, 0, MAX(text_len-1,0) );
592
if ( debug ) dump( stdout, "-> UPDATE SS" );
594
if ( insertion_pt >= 0 AND
595
insertion_pt < substring_start ) { /* cursor moved left */
596
substring_start = insertion_pt;
598
while ( substring_width( substring_start, substring_end ) > box_width )
601
else if ( insertion_pt > substring_end ) { /* cursor moved right */
602
substring_end = insertion_pt-1;
604
while ( substring_width( substring_start, substring_end ) > box_width )
607
else { /* cursor is within old substring bounds */
608
if ( last_insertion_pt > insertion_pt ) { /* cursor moved left */
611
while ( substring_width( substring_start, substring_end ) > box_width )
614
while(substring_end < text_len-1
615
AND substring_width( substring_start, substring_end ) <= box_width)
620
while ( substring_width( substring_start, substring_end ) > box_width )
623
last_insertion_pt = insertion_pt;
625
/*** No selection if not enabled ***/
627
sel_start = sel_end = 0;
630
if ( debug ) dump( stdout, "<- UPDATE SS" );
632
if ( substring_start == old_start AND substring_end == old_end )
633
return false; /*** bounds did not change ***/
635
return true; /*** bounds did change ***/
639
/********************************* GLUI_EditText::update_x_offsets() *********/
641
void GLUI_EditText::update_x_offsets( void )
646
/********************************* GLUI_EditText::draw_text() ****************/
648
void GLUI_EditText::draw_text( int x, int y )
650
GLUI_DRAWINGSENTINAL_IDIOM
651
int text_x, i, sel_lo, sel_hi;
653
if ( debug ) dump( stdout, "-> DRAW_TEXT" );
655
if ( NOT draw_text_only ) {
657
glColor3f( 1., 1., 1. );
660
glDisable( GL_CULL_FACE );
662
glVertex2i( text_x_offset+2, 2 ); glVertex2i( w-2, 2 );
663
glVertex2i( w-2, h-2 ); glVertex2i( text_x_offset+2, h-2 );
667
/** Find where to draw the text **/
669
text_x = text_x_offset + 2 + GLUI_EDITTEXT_BOXINNERMARGINX;
671
/*printf( "text_x: %d substr_width: %d start/end: %d/%d\n",
672
text_x, substring_width( substring_start, substring_end ),
673
substring_start, substring_end );
675
/** Find lower and upper selection bounds **/
676
sel_lo = MIN(sel_start, sel_end );
677
sel_hi = MAX(sel_start, sel_end );
679
int sel_x_start, sel_x_end, delta;
681
/** Draw selection area dark **/
682
if ( sel_start != sel_end ) {
683
sel_x_start = text_x;
685
for( i=substring_start; i<=substring_end; i++ ) {
686
delta = char_width( text[i] );
689
sel_x_start += delta;
692
else if ( i < sel_hi ) {
697
glColor3f( 0.0f, 0.0f, .6f );
699
glVertex2i( sel_x_start, 2 ); glVertex2i( sel_x_end, 2 );
700
glVertex2i( sel_x_end, h-2 ); glVertex2i( sel_x_start, h-2 );
705
if ( sel_start == sel_end ) { /* No current selection */
707
glColor3b( 0, 0, 0 );
709
glColor3b( 32, 32, 32 );
711
glRasterPos2i( text_x, 13);
712
for( i=substring_start; i<=substring_end; i++ ) {
713
glutBitmapCharacter( get_font(), this->text[i] );
716
else { /* There is a selection */
718
for( i=substring_start; i<=substring_end; i++ ) {
719
if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { /* This character is selected */
720
glColor3f( 1., 1., 1. );
721
glRasterPos2i( x, 13);
722
glutBitmapCharacter( get_font(), this->text[i] );
725
glColor3f( 0., 0., 0. );
726
glRasterPos2i( x, 13);
727
glutBitmapCharacter( get_font(), this->text[i] );
730
x += char_width( text[i] );
734
if ( debug ) dump( stdout, "<- DRAW_TEXT" );
738
/******************************** GLUI_EditText::find_insertion_pt() *********/
739
/* This function returns the character numer *before which* the insertion */
742
int GLUI_EditText::find_insertion_pt( int x, int y )
746
/*** See if we clicked outside box ***/
747
if ( x < this->x_abs + text_x_offset )
750
/* We move from right to left, looking to see if the mouse was clicked
751
to the right of the ith character */
753
curr_x = this->x_abs + text_x_offset
754
+ substring_width( substring_start, substring_end )
755
+ 2 /* The edittext box has a 2-pixel margin */
756
+ GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space
757
between the text and the box **/
759
/*** See if we clicked in an empty box ***/
760
if ( (int) text.length() == 0 )
763
/** find mouse click in text **/
764
for( i=substring_end; i>=substring_start; i-- ) {
765
curr_x -= char_width( text[i] );
768
/* printf( "-> %d\n", i ); */
776
/* Well, the mouse wasn't after any of the characters...see if it's
777
before the beginning of the substring */
779
if ( x > (x_abs + text_x_offset + 2 ) )
780
return substring_start;
782
return -1; /* Nothing found */
787
/******************************** GLUI_EditText::draw_insertion_pt() *********/
789
void GLUI_EditText::draw_insertion_pt( void )
793
if ( NOT can_draw() )
796
/*** Don't draw insertion pt if control is disabled ***/
800
if ( debug ) dump( stdout, "-> DRAW_INS_PT" );
802
if ( sel_start != sel_end OR insertion_pt < 0 ) {
803
return; /* Don't draw insertion point if there is a current selection */
806
/* printf( "insertion pt: %d\n", insertion_pt ); */
808
curr_x = this->x_abs + text_x_offset
809
+ substring_width( substring_start, substring_end )
810
+ 2 /* The edittext box has a 2-pixel margin */
811
+ GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space
812
between the text and the box **/
814
for( i=substring_end; i>=insertion_pt; i-- ) {
815
curr_x -= char_width( text[i] );
818
glColor3f( 0.0, 0.0, 0.0 );
819
glBegin( GL_LINE_LOOP );
821
glVertex2i( curr_x, y_abs + 4 );
822
glVertex2i( curr_x, y_abs + 4 );
823
glVertex2i( curr_x, y_abs + h - 3 );
824
glVertex2i( curr_x, y_abs + h - 3 );
827
glVertex2i( curr_x, 0 + 4 );
828
glVertex2i( curr_x, 0 + 4 );
829
glVertex2i( curr_x, 0 + h - 3 );
830
glVertex2i( curr_x, 0 + h - 3 );
833
if ( debug ) dump( stdout, "-> DRAW_INS_PT" );
838
/******************************** GLUI_EditText::substring_width() *********/
840
int GLUI_EditText::substring_width( int start, int end )
846
for( i=start; i<=end; i++ )
847
width += char_width( text[i] );
853
/***************************** GLUI_EditText::update_and_draw_text() ********/
855
void GLUI_EditText::update_and_draw_text( void )
857
if ( NOT can_draw() )
860
update_substring_bounds();
861
/* printf( "ss: %d/%d\n", substring_start, substring_end ); */
867
/********************************* GLUI_EditText::special_handler() **********/
869
int GLUI_EditText::special_handler( int key,int modifiers )
875
printf( "SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n",
876
key, modifiers, substring_start, substring_end,insertion_pt,
877
sel_start, sel_end );
879
if ( key == GLUT_KEY_LEFT ) {
880
if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
881
insertion_pt = find_word_break( insertion_pt, -1 );
887
else if ( key == GLUT_KEY_RIGHT ) {
888
if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
889
insertion_pt = find_word_break( insertion_pt, +1 );
895
else if ( key == GLUT_KEY_HOME ) {
898
else if ( key == GLUT_KEY_END ) {
899
insertion_pt = (int) text.length();
902
/*** Update selection if shift key is down ***/
903
if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 )
904
sel_end = insertion_pt;
906
sel_start = sel_end = insertion_pt;
909
CLAMP( insertion_pt, 0, (int) text.length()); /* Make sure insertion_pt
911
CLAMP( sel_start, 0, (int) text.length()); /* Make sure insertion_pt
913
CLAMP( sel_end, 0, (int) text.length()); /* Make sure insertion_pt
916
/******** Now redraw text ***********/
918
update_and_draw_text();
924
/****************************** GLUI_EditText::find_word_break() **********/
925
/* It looks either left or right (depending on value of 'direction' */
926
/* for the beginning of the next 'word', where word are characters */
927
/* separated by one of the following tokens: " :-.," */
928
/* If there is no next word in the specified direction, this returns */
929
/* the beginning of 'text', or the very end. */
931
int GLUI_EditText::find_word_break( int start, int direction )
934
char *breaks = " :-.,";
935
int num_break_chars = (int)strlen(breaks), text_len = (int)text.length();
938
/** If we're moving left, we have to start two back, in case we're either
939
already at the beginning of a word, or on a separating token.
940
Otherwise, this function would just return the word we're already at **/
941
if ( direction == -1 ) {
945
/***** Iterate over text in the specified direction *****/
946
for ( i=start; i >= 0 AND i < text_len; i += direction ) {
948
/** For each character in text, iterate over list of separating tokens **/
949
for( j=0; j<num_break_chars; j++ ) {
950
if ( text[i] == breaks[j] ) {
952
/** character 'i' is a separating token, so we return i+1 **/
955
CLAMP( new_pt, 0, text_len );
962
if ( direction > 0 ) /* Return the end of string */
964
else /* Return the beginning of the text */
969
/********************************** GLUI_EditText::clear_substring() ********/
971
void GLUI_EditText::clear_substring( int start, int end )
976
printf( "clearing: %d-%d '", start,end);
977
for(i=start;i<end;i++ )
979
printf( "'\n" ); flushout;
981
/*** See if we're deleting a period in a float data-type box ***/
982
if ( data_type == GLUI_EDITTEXT_FLOAT ) {
983
for( i=start; i<end; i++ )
984
if ( text[i] == '.' )
988
text.erase(start,end-start);
993
/************************************ GLUI_EditText::update_size() **********/
995
void GLUI_EditText::update_size( void )
997
int text_size, delta;
1002
text_size = string_width( name );
1005
if ( text_x_offset < text_size +2 )
1006
delta = text_size+2-text_x_offset;
1008
text_x_offset += delta;
1011
if ( data_type == GLUI_EDITTEXT_TEXT OR
1012
data_type == GLUI_EDITTEXT_FLOAT) {
1013
if ( w < text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH )
1014
w = text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH;
1016
else if ( data_type == GLUI_EDITTEXT_INT ) {
1017
if ( w < text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH )
1018
w = text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH;
1023
/****************************** GLUI_EditText::set_text() **********/
1025
void GLUI_EditText::set_text( const char *new_text )
1028
substring_start = 0;
1029
substring_end = (int) text.length() - 1;
1035
update_and_draw_text();
1037
/** Update the spinner, if we have one **/
1039
spinner->float_val = this->float_val;
1040
spinner->int_val = this->int_val;
1043
/*** Now update the live variable ***/
1048
/******************************* GLUI_EditText::set_float_val() ************/
1050
void GLUI_EditText::set_float_val( float new_val )
1052
if ( has_limits == GLUI_LIMIT_CLAMP ) {
1053
/*** Clamp the new value to the existing limits ***/
1055
CLAMP( new_val, float_low, float_high );
1057
else if ( has_limits == GLUI_LIMIT_WRAP ) {
1058
/*** Clamp the value cyclically to the limits - that is, if the
1059
value exceeds the max, set it the the minimum, and conversely ***/
1061
if ( new_val < float_low )
1062
new_val = float_high;
1063
if ( new_val > float_high )
1064
new_val = float_low;
1067
float_val = new_val;
1068
int_val = (int) new_val; /* Mirror the value as an int, too */
1074
/********************************** GLUI_EditText::set_int_val() ************/
1076
void GLUI_EditText::set_int_val( int new_val )
1078
if ( has_limits == GLUI_LIMIT_CLAMP ) {
1079
/*** Clamp the new value to the existing limits ***/
1081
CLAMP( new_val, int_low, int_high );
1083
else if ( has_limits == GLUI_LIMIT_WRAP ) {
1084
/*** Clamp the value cyclically to the limits - that is, if the
1085
value exceeds the max, set it the the minimum, and conversely ***/
1087
if ( new_val < int_low )
1089
if ( new_val > int_high )
1094
float_val = (float) new_val; /* We mirror the value as a float, too */
1100
/********************************* GLUI_EditText::set_float_limits() *********/
1102
void GLUI_EditText::set_float_limits( float low, float high, int limit_type )
1104
has_limits = limit_type;
1108
if ( NOT IN_BOUNDS( float_val, float_low, float_high ))
1109
set_float_val( float_low );
1111
int_low = (int) float_low;
1112
int_high = (int) float_high;
1116
/*********************************** GLUI_EditText::set_int_limits() *********/
1118
void GLUI_EditText::set_int_limits( int low, int high, int limit_type )
1120
has_limits = limit_type;
1124
if ( NOT IN_BOUNDS( int_val, int_low, int_high ))
1125
set_int_val( int_low );
1127
float_low = (float) int_low;
1128
float_high = (float) int_high;
1132
/************************************ GLUI_EditText::set_numeric_text() ******/
1134
void GLUI_EditText::set_numeric_text( void )
1139
if ( data_type == GLUI_EDITTEXT_FLOAT ) {
1140
sprintf( buf_num, "%#g", float_val );
1143
text_len = (int) strlen(buf_num);
1144
for ( i=0; i<text_len; i++ )
1145
if ( buf_num[i] == '.' )
1148
/* Now remove trailing zeros */
1149
if ( num_periods > 0 ) {
1150
text_len = (int) strlen(buf_num);
1151
for ( i=text_len-1; i>0; i-- ) {
1152
if ( buf_num[i] == '0' AND buf_num[i-1] != '.' )
1158
set_text( buf_num );
1161
sprintf( buf_num, "%d", int_val );
1162
set_text( buf_num );
1168
/*************************************** GLUI_EditText::dump() **************/
1170
void GLUI_EditText::dump( FILE *out, const char *name )
1173
"%s (edittext@%p): ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n",
1180
(int) text.length());
1184
/**************************************** GLUI_EditText::mouse_over() ********/
1186
int GLUI_EditText::mouse_over( int state, int x, int y )
1189
/* curr_cursor = GLUT_CURSOR_TEXT; */
1190
glutSetCursor( GLUT_CURSOR_TEXT );
1193
/* printf( "OUT\n" ); */
1194
glutSetCursor( GLUT_CURSOR_LEFT_ARROW );