1044 lines
27 KiB
C++
1044 lines
27 KiB
C++
/****************************************************************************
|
|
|
|
GLUI User Interface Toolkit
|
|
---------------------------
|
|
|
|
glui_edittext.cpp - GLUI_EditText control class
|
|
|
|
|
|
--------------------------------------------------
|
|
|
|
Copyright (c) 1998 Paul Rademacher
|
|
|
|
This program is freely distributable without licensing fees and is
|
|
provided without guarantee or warrantee expressed or implied. This
|
|
program is -not- in the public domain.
|
|
|
|
*****************************************************************************/
|
|
|
|
#include "glui.h"
|
|
#include "stdinc.h"
|
|
|
|
/****************************** GLUI_EditText::mouse_down_handler() **********/
|
|
|
|
int GLUI_EditText::mouse_down_handler( int local_x, int local_y )
|
|
{
|
|
int tmp_insertion_pt;
|
|
|
|
if ( debug ) dump( stdout, "-> MOUSE DOWN" );
|
|
|
|
tmp_insertion_pt = find_insertion_pt( local_x, local_y );
|
|
if ( tmp_insertion_pt == -1 ) {
|
|
if ( glui )
|
|
glui->disactivate_current_control( );
|
|
return false;
|
|
}
|
|
|
|
insertion_pt = tmp_insertion_pt;
|
|
|
|
sel_start = sel_end = insertion_pt;
|
|
|
|
if ( can_draw())
|
|
update_and_draw_text();
|
|
|
|
if ( debug ) dump( stdout, "<- MOUSE UP" );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/******************************** GLUI_EditText::mouse_up_handler() **********/
|
|
|
|
int GLUI_EditText::mouse_up_handler( int local_x, int local_y, int inside )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
/***************************** GLUI_EditText::mouse_held_down_handler() ******/
|
|
|
|
int GLUI_EditText::mouse_held_down_handler( int local_x, int local_y,
|
|
int new_inside)
|
|
{
|
|
int tmp_pt;
|
|
|
|
if ( NOT new_inside )
|
|
return false;
|
|
|
|
if ( debug ) dump( stdout, "-> HELD DOWN" );
|
|
|
|
tmp_pt = find_insertion_pt( local_x, local_y );
|
|
|
|
if ( tmp_pt == -1 AND sel_end != 0 ) { /* moved mouse past left edge */
|
|
special_handler( GLUT_KEY_LEFT, GLUT_ACTIVE_SHIFT );
|
|
}
|
|
else if ( tmp_pt == substring_end+1 AND sel_end != (int) strlen(text)) {
|
|
/* moved mouse past right edge */
|
|
special_handler( GLUT_KEY_RIGHT, GLUT_ACTIVE_SHIFT );
|
|
}
|
|
else if ( tmp_pt != -1 AND tmp_pt != sel_end ) {
|
|
sel_end = insertion_pt = tmp_pt;
|
|
|
|
update_and_draw_text();
|
|
}
|
|
|
|
if ( debug )
|
|
dump( stdout, "<- HELD DOWN" );
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/****************************** GLUI_EditText::key_handler() **********/
|
|
|
|
int GLUI_EditText::key_handler( unsigned char key,int modifiers )
|
|
{
|
|
int i, regular_key;
|
|
/* int has_selection; */
|
|
|
|
if ( NOT glui )
|
|
return false;
|
|
|
|
if ( debug )
|
|
dump( stdout, "-> KEY HANDLER" );
|
|
|
|
regular_key = false;
|
|
/* has_selection = (sel_start != sel_end); */
|
|
|
|
if ( key == 21 AND (modifiers & GLUT_ACTIVE_CTRL )!=0) { /* DEL all text */
|
|
/** This one (key==21) may not port!! */
|
|
|
|
insertion_pt = -1;
|
|
text[0] = '\0';
|
|
sel_start = sel_end = -1;
|
|
}
|
|
else if ( key == 13 ) { /* RETURN */
|
|
/* glui->disactivate_current_control(); */
|
|
disactivate(); /** Force callbacks, etc **/
|
|
activate(GLUI_ACTIVATE_TAB); /** Reselect all text **/
|
|
translate_and_draw_front();
|
|
return true;
|
|
}
|
|
else if ( key == 27 ) { /* ESCAPE */
|
|
glui->disactivate_current_control();
|
|
return true;
|
|
}
|
|
else if ( key == 8 ) { /* BACKSPACE */
|
|
if ( sel_start == sel_end ) { /* no selection */
|
|
if ( insertion_pt > 0 ) {
|
|
/*** See if we're deleting a period in a float data-type box ***/
|
|
if ( data_type == GLUI_EDITTEXT_FLOAT AND text[insertion_pt-1]=='.' )
|
|
num_periods--;
|
|
|
|
/*** Shift over string first ***/
|
|
insertion_pt--;
|
|
for( i=insertion_pt; i< (int)strlen( text ); i++ )
|
|
text[i] = text[i+1];
|
|
}
|
|
}
|
|
else { /* There is a selection */
|
|
clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
|
|
insertion_pt = MIN(sel_start,sel_end);
|
|
sel_start = sel_end = insertion_pt;
|
|
}
|
|
}
|
|
else { /* Regular key */
|
|
regular_key = true;
|
|
|
|
/** Check if we only accept numbers **/
|
|
if (data_type == GLUI_EDITTEXT_FLOAT ) {
|
|
if ( (key < '0' OR key > '9') AND key != '.' AND key != '-' )
|
|
return true;
|
|
|
|
if ( key == '-' ) { /* User typed a '-' */
|
|
|
|
/* If user has first character selected, then '-' is allowed */
|
|
if ( NOT ( MIN(sel_start,sel_end) == 0 AND
|
|
MAX(sel_start,sel_end) > 0 ) ) {
|
|
|
|
/* User does not have 1st char selected */
|
|
if (insertion_pt != 0 OR text[0] == '-' ) {
|
|
return true; /* Can only place negative at beginning of text,
|
|
and only one of them */
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( key == '.' ) {
|
|
/*printf( "PERIOD: %d\n", num_periods ); */
|
|
|
|
if ( num_periods > 0 ) {
|
|
/** We're trying to type a period, but the text already contains
|
|
a period. Check whether the period is contained within
|
|
is current selection (thus it will be safely replaced) **/
|
|
|
|
int period_found = false;
|
|
if ( sel_start != sel_end ) {
|
|
for( i=MIN(sel_end,sel_start); i<MAX(sel_start,sel_end); i++ ) {
|
|
/* printf( "%c ", text[i] ); */
|
|
if ( text[i] == '.' ) {
|
|
period_found = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* printf( "found: %d num: %d\n", period_found, num_periods ); */
|
|
|
|
if ( NOT period_found )
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
else if (data_type == GLUI_EDITTEXT_INT)
|
|
{
|
|
if ( (key < '0' OR key > '9') AND key != '-' )
|
|
return true;
|
|
|
|
if ( key == '-' ) { /* User typed a '-' */
|
|
|
|
/* If user has first character selected, then '-' is allowed */
|
|
if ( NOT ( MIN(sel_start,sel_end) == 0 AND
|
|
MAX(sel_start,sel_end) > 0 ) ) {
|
|
|
|
/* User does not have 1st char selected */
|
|
if (insertion_pt != 0 OR text[0] == '-' ) {
|
|
return true; /* Can only place negative at beginning of text,
|
|
and only one of them */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** This is just to get rid of warnings - the flag regular_key is
|
|
set if the key was not a backspace, return, whatever. But I
|
|
believe if we're here, we know it was a regular key anyway */
|
|
if ( regular_key ) {
|
|
}
|
|
|
|
/**** If there's a current selection, erase it ******/
|
|
if ( sel_start != sel_end ) {
|
|
clear_substring( MIN(sel_start,sel_end), MAX(sel_start,sel_end ));
|
|
insertion_pt = MIN(sel_start,sel_end);
|
|
sel_start = sel_end = insertion_pt;
|
|
}
|
|
|
|
/******** check whether we have space ******/
|
|
if ( (unsigned int)strlen( text ) + 2 >= sizeof( GLUI_String ))
|
|
return false;
|
|
|
|
/******** We insert the character into the string ***/
|
|
|
|
/*** Shift over string first ***/
|
|
for( i=(int)strlen( text ); i >= insertion_pt; i-- )
|
|
text[i+1] = text[i];
|
|
|
|
/******** Now insert the character ********/
|
|
text[insertion_pt] = key;
|
|
|
|
/******** Move the insertion point and substring_end one over ******/
|
|
insertion_pt++;
|
|
substring_end++;
|
|
|
|
sel_start = sel_end = insertion_pt;
|
|
}
|
|
|
|
/******** Now redraw text ***********/
|
|
/* Hack to prevent text box from being cleared first **/
|
|
/** int substring_change = update_substring_bounds();
|
|
draw_text_only =
|
|
(NOT substring_change AND NOT has_selection AND regular_key );
|
|
*/
|
|
|
|
draw_text_only = false; /** Well, hack is not yet working **/
|
|
update_and_draw_text();
|
|
draw_text_only = false;
|
|
|
|
|
|
if ( debug )
|
|
dump( stdout, "<- KEY HANDLER" );
|
|
|
|
/*** Now look to see if this string has a period ***/
|
|
num_periods = 0;
|
|
for( i=0; i<(int)strlen(text); i++ )
|
|
if ( text[i] == '.' )
|
|
num_periods++;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/****************************** GLUI_EditText::activate() **********/
|
|
|
|
void GLUI_EditText::activate( int how )
|
|
{
|
|
if ( debug )
|
|
dump( stdout, "-> ACTIVATE" );
|
|
|
|
active = true;
|
|
|
|
if ( how == GLUI_ACTIVATE_MOUSE )
|
|
return; /* Don't select everything if activated with mouse */
|
|
|
|
strcpy( orig_text, text );
|
|
|
|
sel_start = 0;
|
|
sel_end = (int)strlen(text);
|
|
insertion_pt = 0;
|
|
|
|
if ( debug )
|
|
dump( stdout, "<- ACTIVATE" );
|
|
}
|
|
|
|
|
|
/****************************** GLUI_EditText::disactivate() **********/
|
|
|
|
void GLUI_EditText::disactivate( void )
|
|
{
|
|
int new_int_val;
|
|
float new_float_val;
|
|
|
|
active = false;
|
|
|
|
if ( NOT glui )
|
|
return;
|
|
|
|
if ( debug )
|
|
dump( stdout, "-> DISACTIVATE" );
|
|
|
|
sel_start = sel_end = insertion_pt = -1;
|
|
|
|
/***** Retrieve the current value from the text *****/
|
|
/***** The live variable will be updated by set_text() ****/
|
|
if ( data_type == GLUI_EDITTEXT_FLOAT ) {
|
|
if ( text[0] == '\0' ) /* zero-length string - make it "0.0" */
|
|
strcpy( text, "0.0" );
|
|
|
|
new_float_val = atof( text );
|
|
|
|
set_float_val( new_float_val );
|
|
}
|
|
else if ( data_type == GLUI_EDITTEXT_INT ) {
|
|
if ( text[0] == '\0' ) /* zero-length string - make it "0" */
|
|
strcpy( text, "0" );
|
|
|
|
new_int_val = atoi( text );
|
|
|
|
set_int_val( new_int_val );
|
|
}
|
|
else
|
|
if ( data_type == GLUI_EDITTEXT_TEXT ) {
|
|
set_text(text); /* This will force callbacks and gfx refresh */
|
|
}
|
|
|
|
update_substring_bounds();
|
|
|
|
/******** redraw text without insertion point ***********/
|
|
translate_and_draw_front();
|
|
|
|
/***** Now do callbacks if value changed ******/
|
|
if ( strcmp( orig_text, text ) != 0 ) {
|
|
this->execute_callback();
|
|
|
|
if ( 0 ) {
|
|
/* THE CODE BELOW IS FROM WHEN SPINNER ALSO MAINTAINED CALLBACKS */
|
|
if ( spinner == NULL ) { /** Are we independent of a spinner? **/
|
|
if ( callback ) {
|
|
callback( this->user_id );
|
|
}
|
|
}
|
|
else { /* We're attached to a spinner */
|
|
spinner->do_callbacks(); /* Let the spinner do the callback stuff */
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( debug )
|
|
dump( stdout, "<- DISACTIVATE" );
|
|
}
|
|
|
|
/****************************** GLUI_EditText::draw() **********/
|
|
|
|
void GLUI_EditText::draw( int x, int y )
|
|
{
|
|
int orig;
|
|
int name_x;
|
|
|
|
if ( NOT can_draw() )
|
|
return;
|
|
|
|
orig = set_to_glut_window();
|
|
|
|
name_x = MAX(text_x_offset - string_width(this->name) - 3,0);
|
|
draw_name( name_x , 13);
|
|
|
|
glBegin( GL_LINES );
|
|
glColor3f( .5, .5, .5 );
|
|
glVertex2i( text_x_offset, 0 ); glVertex2i( w, 0 );
|
|
glVertex2i( text_x_offset, 0 ); glVertex2i( text_x_offset, h );
|
|
|
|
glColor3f( 1., 1., 1. );
|
|
glVertex2i( text_x_offset, h ); glVertex2i( w, h );
|
|
glVertex2i( w, h ); glVertex2i( w, 0 );
|
|
|
|
if ( enabled )
|
|
glColor3f( 0., 0., 0. );
|
|
else
|
|
glColor3f( .25, .25, .25 );
|
|
glVertex2i( text_x_offset+1, 1 ); glVertex2i( w-1, 1 );
|
|
glVertex2i( text_x_offset+1, 1 ); glVertex2i( text_x_offset+1, h-1 );
|
|
|
|
glColor3f( .75, .75, .75 );
|
|
glVertex2i( text_x_offset+1, h-1 ); glVertex2i( w-1, h-1 );
|
|
glVertex2i( w-1, h-1 ); glVertex2i( w-1, 1 );
|
|
glEnd();
|
|
|
|
/** Find where to draw the text **/
|
|
update_substring_bounds();
|
|
draw_text(0,0);
|
|
|
|
draw_insertion_pt();
|
|
|
|
restore_window(orig);
|
|
}
|
|
|
|
|
|
|
|
/************************** GLUI_EditText::update_substring_bounds() *********/
|
|
|
|
int GLUI_EditText::update_substring_bounds( void )
|
|
{
|
|
int box_width;
|
|
int text_len = (int)strlen(text);
|
|
int old_start, old_end;
|
|
|
|
old_start = substring_start;
|
|
old_end = substring_end;
|
|
|
|
/*** Calculate the width of the usable area of the edit box ***/
|
|
box_width = MAX( this->w - this->text_x_offset
|
|
- 4 /* 2 * the two-line box border */
|
|
- 2 * GLUI_EDITTEXT_BOXINNERMARGINX, 0 );
|
|
|
|
CLAMP( substring_end, 0, MAX(text_len-1,0) );
|
|
CLAMP( substring_start, 0, MAX(text_len-1,0) );
|
|
|
|
if ( debug ) dump( stdout, "-> UPDATE SS" );
|
|
|
|
if ( insertion_pt >= 0 AND
|
|
insertion_pt < substring_start ) { /* cursor moved left */
|
|
substring_start = insertion_pt;
|
|
|
|
while ( substring_width( substring_start, substring_end ) > box_width )
|
|
substring_end--;
|
|
}
|
|
else if ( insertion_pt > substring_end ) { /* cursor moved right */
|
|
substring_end = insertion_pt-1;
|
|
|
|
while ( substring_width( substring_start, substring_end ) > box_width )
|
|
substring_start++;
|
|
}
|
|
else { /* cursor is within old substring bounds */
|
|
if ( last_insertion_pt > insertion_pt ) { /* cursor moved left */
|
|
}
|
|
else {
|
|
while ( substring_width( substring_start, substring_end ) > box_width )
|
|
substring_end--;
|
|
|
|
while(substring_width( substring_start, substring_end+1 ) <= box_width
|
|
AND substring_end < text_len-1 )
|
|
substring_end++;
|
|
}
|
|
}
|
|
|
|
while ( substring_width( substring_start, substring_end ) > box_width )
|
|
substring_end--;
|
|
|
|
last_insertion_pt = insertion_pt;
|
|
|
|
/*** No selection if not enabled ***/
|
|
if ( NOT enabled ) {
|
|
sel_start = sel_end = 0;
|
|
}
|
|
|
|
if ( debug ) dump( stdout, "<- UPDATE SS" );
|
|
|
|
if ( substring_start == old_start AND substring_end == old_end )
|
|
return false; /*** bounds did not change ***/
|
|
else
|
|
return true; /*** bounds did change ***/
|
|
}
|
|
|
|
|
|
/********************************* GLUI_EditText::update_x_offsets() *********/
|
|
|
|
void GLUI_EditText::update_x_offsets( void )
|
|
{
|
|
}
|
|
|
|
|
|
/********************************* GLUI_EditText::draw_text() ****************/
|
|
|
|
void GLUI_EditText::draw_text( int x, int y )
|
|
{
|
|
int text_x, i, sel_lo, sel_hi;
|
|
int orig;
|
|
|
|
if ( NOT can_draw() )
|
|
return;
|
|
|
|
if ( debug ) dump( stdout, "-> DRAW_TEXT" );
|
|
|
|
orig = set_to_glut_window();
|
|
|
|
if ( NOT draw_text_only ) {
|
|
if ( enabled )
|
|
glColor3f( 1., 1., 1. );
|
|
else
|
|
set_to_bkgd_color();
|
|
glDisable( GL_CULL_FACE );
|
|
glBegin( GL_QUADS );
|
|
glVertex2i( text_x_offset+2, 2 ); glVertex2i( w-2, 2 );
|
|
glVertex2i( w-2, h-2 ); glVertex2i( text_x_offset+2, h-2 );
|
|
glEnd();
|
|
}
|
|
|
|
/** Find where to draw the text **/
|
|
|
|
text_x = text_x_offset + 2 + GLUI_EDITTEXT_BOXINNERMARGINX;
|
|
|
|
/*printf( "text_x: %d substr_width: %d start/end: %d/%d\n",
|
|
text_x, substring_width( substring_start, substring_end ),
|
|
substring_start, substring_end );
|
|
*/
|
|
/** Find lower and upper selection bounds **/
|
|
sel_lo = MIN(sel_start, sel_end );
|
|
sel_hi = MAX(sel_start, sel_end );
|
|
|
|
int sel_x_start, sel_x_end, delta;
|
|
|
|
/** Draw selection area dark **/
|
|
if ( sel_start != sel_end ) {
|
|
sel_x_start = text_x;
|
|
sel_x_end = text_x;
|
|
for( i=substring_start; i<=substring_end; i++ ) {
|
|
delta = char_width( text[i] );
|
|
|
|
if ( i < sel_lo ) {
|
|
sel_x_start += delta;
|
|
sel_x_end += delta;
|
|
}
|
|
else if ( i < sel_hi ) {
|
|
sel_x_end += delta;
|
|
}
|
|
}
|
|
|
|
glColor3f( 0.0f, 0.0f, .6f );
|
|
glBegin( GL_QUADS );
|
|
glVertex2i( sel_x_start, 2 ); glVertex2i( sel_x_end, 2 );
|
|
glVertex2i( sel_x_end, h-2 ); glVertex2i( sel_x_start, h-2 );
|
|
glEnd();
|
|
}
|
|
|
|
|
|
if ( sel_start == sel_end ) { /* No current selection */
|
|
if ( enabled )
|
|
glColor3b( 0, 0, 0 );
|
|
else
|
|
glColor3b( 32, 32, 32 );
|
|
|
|
glRasterPos2i( text_x, 13);
|
|
for( i=substring_start; i<=substring_end; i++ ) {
|
|
glutBitmapCharacter( get_font(), this->text[i] );
|
|
}
|
|
}
|
|
else { /* There is a selection */
|
|
int x = text_x;
|
|
for( i=substring_start; i<=substring_end; i++ ) {
|
|
if ( IN_BOUNDS( i, sel_lo, sel_hi-1)) { /* This character is selected */
|
|
glColor3f( 1., 1., 1. );
|
|
glRasterPos2i( x, 13);
|
|
glutBitmapCharacter( get_font(), this->text[i] );
|
|
}
|
|
else {
|
|
glColor3f( 0., 0., 0. );
|
|
glRasterPos2i( x, 13);
|
|
glutBitmapCharacter( get_font(), this->text[i] );
|
|
}
|
|
|
|
x += char_width( text[i] );
|
|
}
|
|
}
|
|
|
|
restore_window( orig );
|
|
|
|
if ( debug ) dump( stdout, "<- DRAW_TEXT" );
|
|
}
|
|
|
|
|
|
/******************************** GLUI_EditText::find_insertion_pt() *********/
|
|
/* This function returns the character numer *before which* the insertion */
|
|
/* point goes */
|
|
|
|
int GLUI_EditText::find_insertion_pt( int x, int y )
|
|
{
|
|
int curr_x, i;
|
|
|
|
/*** See if we clicked outside box ***/
|
|
if ( x < this->x_abs + text_x_offset )
|
|
return -1;
|
|
|
|
/* We move from right to left, looking to see if the mouse was clicked
|
|
to the right of the ith character */
|
|
|
|
curr_x = this->x_abs + text_x_offset
|
|
+ substring_width( substring_start, substring_end )
|
|
+ 2 /* The edittext box has a 2-pixel margin */
|
|
+ GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space
|
|
between the text and the box **/
|
|
|
|
/*** See if we clicked in an empty box ***/
|
|
if ( (int)strlen( text ) == 0 )
|
|
return 0;
|
|
|
|
/** find mouse click in text **/
|
|
for( i=substring_end; i>=substring_start; i-- ) {
|
|
curr_x -= char_width( text[i] );
|
|
|
|
if ( x > curr_x ) {
|
|
/* printf( "-> %d\n", i ); */
|
|
|
|
return i+1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
/* Well, the mouse wasn't after any of the characters...see if it's
|
|
before the beginning of the substring */
|
|
if ( 0 ) {
|
|
if ( x > (x_abs + text_x_offset + 2 ) )
|
|
return substring_start;
|
|
|
|
return -1; /* Nothing found */
|
|
}
|
|
}
|
|
|
|
|
|
/******************************** GLUI_EditText::draw_insertion_pt() *********/
|
|
|
|
void GLUI_EditText::draw_insertion_pt( void )
|
|
{
|
|
int curr_x, i;
|
|
|
|
if ( NOT can_draw() )
|
|
return;
|
|
|
|
/*** Don't draw insertion pt if control is disabled ***/
|
|
if ( NOT enabled )
|
|
return;
|
|
|
|
if ( debug ) dump( stdout, "-> DRAW_INS_PT" );
|
|
|
|
if ( sel_start != sel_end OR insertion_pt < 0 ) {
|
|
return; /* Don't draw insertion point if there is a current selection */
|
|
}
|
|
|
|
/* printf( "insertion pt: %d\n", insertion_pt ); */
|
|
|
|
curr_x = this->x_abs + text_x_offset
|
|
+ substring_width( substring_start, substring_end )
|
|
+ 2 /* The edittext box has a 2-pixel margin */
|
|
+ GLUI_EDITTEXT_BOXINNERMARGINX; /** plus this many pixels blank space
|
|
between the text and the box **/
|
|
|
|
for( i=substring_end; i>=insertion_pt; i-- ) {
|
|
curr_x -= char_width( text[i] );
|
|
}
|
|
|
|
glColor3f( 0.0, 0.0, 0.0 );
|
|
glBegin( GL_LINE_LOOP );
|
|
/***
|
|
glVertex2i( curr_x, y_abs + 4 );
|
|
glVertex2i( curr_x, y_abs + 4 );
|
|
glVertex2i( curr_x, y_abs + h - 3 );
|
|
glVertex2i( curr_x, y_abs + h - 3 );
|
|
***/
|
|
curr_x -= x_abs;
|
|
glVertex2i( curr_x, 0 + 4 );
|
|
glVertex2i( curr_x, 0 + 4 );
|
|
glVertex2i( curr_x, 0 + h - 3 );
|
|
glVertex2i( curr_x, 0 + h - 3 );
|
|
glEnd();
|
|
|
|
if ( debug ) dump( stdout, "-> DRAW_INS_PT" );
|
|
}
|
|
|
|
|
|
|
|
/******************************** GLUI_EditText::substring_width() *********/
|
|
|
|
int GLUI_EditText::substring_width( int start, int end )
|
|
{
|
|
int i, width;
|
|
|
|
width = 0;
|
|
|
|
for( i=start; i<=end; i++ )
|
|
width += char_width( text[i] );
|
|
|
|
return width;
|
|
}
|
|
|
|
|
|
/***************************** GLUI_EditText::update_and_draw_text() ********/
|
|
|
|
void GLUI_EditText::update_and_draw_text( void )
|
|
{
|
|
if ( NOT can_draw() )
|
|
return;
|
|
|
|
update_substring_bounds();
|
|
/* printf( "ss: %d/%d\n", substring_start, substring_end ); */
|
|
|
|
translate_and_draw_front();
|
|
}
|
|
|
|
|
|
/********************************* GLUI_EditText::special_handler() **********/
|
|
|
|
int GLUI_EditText::special_handler( int key,int modifiers )
|
|
{
|
|
if ( NOT glui )
|
|
return false;
|
|
|
|
if ( 0 )
|
|
printf( "SPECIAL:%d - mod:%d subs:%d/%d ins:%d sel:%d/%d\n",
|
|
key, modifiers, substring_start, substring_end,insertion_pt,
|
|
sel_start, sel_end );
|
|
|
|
if ( key == GLUT_KEY_LEFT ) {
|
|
if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
|
|
insertion_pt = find_word_break( insertion_pt, -1 );
|
|
}
|
|
else {
|
|
insertion_pt--;
|
|
}
|
|
}
|
|
else if ( key == GLUT_KEY_RIGHT ) {
|
|
if ( (modifiers & GLUT_ACTIVE_CTRL) != 0 ) {
|
|
insertion_pt = find_word_break( insertion_pt, +1 );
|
|
}
|
|
else {
|
|
insertion_pt++;
|
|
}
|
|
}
|
|
else if ( key == GLUT_KEY_HOME ) {
|
|
insertion_pt = 0;
|
|
}
|
|
else if ( key == GLUT_KEY_END ) {
|
|
insertion_pt = (int)strlen( text );
|
|
}
|
|
|
|
/*** Update selection if shift key is down ***/
|
|
if ( (modifiers & GLUT_ACTIVE_SHIFT ) != 0 )
|
|
sel_end = insertion_pt;
|
|
else
|
|
sel_start = sel_end = insertion_pt;
|
|
|
|
CLAMP( insertion_pt, 0, (int)strlen( text )); /* Make sure insertion_pt
|
|
is in bounds */
|
|
CLAMP( sel_start, 0, (int)strlen( text )); /* Make sure insertion_pt
|
|
is in bounds */
|
|
CLAMP( sel_end, 0, (int)strlen( text )); /* Make sure insertion_pt
|
|
is in bounds */
|
|
|
|
/******** Now redraw text ***********/
|
|
if ( can_draw())
|
|
update_and_draw_text();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/****************************** GLUI_EditText::find_word_break() **********/
|
|
/* It looks either left or right (depending on value of 'direction' */
|
|
/* for the beginning of the next 'word', where word are characters */
|
|
/* separated by one of the following tokens: " :-.," */
|
|
/* If there is no next word in the specified direction, this returns */
|
|
/* the beginning of 'text', or the very end. */
|
|
|
|
int GLUI_EditText::find_word_break( int start, int direction )
|
|
{
|
|
int i, j;
|
|
char *breaks = " :-.,";
|
|
int num_break_chars = (int)strlen(breaks), text_len = (int)strlen(text);
|
|
int new_pt;
|
|
|
|
/** If we're moving left, we have to start two back, in case we're either
|
|
already at the beginning of a word, or on a separating token.
|
|
Otherwise, this function would just return the word we're already at **/
|
|
if ( direction == -1 ) {
|
|
start -= 2;
|
|
}
|
|
|
|
/***** Iterate over text in the specified direction *****/
|
|
for ( i=start; i >= 0 AND i < text_len; i += direction ) {
|
|
|
|
/** For each character in text, iterate over list of separating tokens **/
|
|
for( j=0; j<num_break_chars; j++ ) {
|
|
if ( text[i] == breaks[j] ) {
|
|
|
|
/** character 'i' is a separating token, so we return i+1 **/
|
|
new_pt = i + 1;
|
|
|
|
CLAMP( new_pt, 0, text_len );
|
|
|
|
return new_pt;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( direction > 0 ) /* Return the end of string */
|
|
return text_len;
|
|
else /* Return the beginning of the text */
|
|
return 0;
|
|
}
|
|
|
|
|
|
/********************************** GLUI_EditText::clear_substring() ********/
|
|
|
|
void GLUI_EditText::clear_substring( int start, int end )
|
|
{
|
|
int i, leftover;
|
|
|
|
/*
|
|
printf( "clearing: %d-%d '", start,end);
|
|
for(i=start;i<end;i++ )
|
|
putchar(text[i]);
|
|
printf( "'\n" ); flushout;
|
|
*/
|
|
/*** See if we're deleting a period in a float data-type box ***/
|
|
if ( data_type == GLUI_EDITTEXT_FLOAT ) {
|
|
for( i=start; i<end; i++ )
|
|
if ( text[i] == '.' )
|
|
num_periods = 0;
|
|
}
|
|
|
|
/*** Shift over string ***/
|
|
leftover = (int)strlen(text) - (end);
|
|
|
|
/* printf( "leftover: %d - ", leftover ); */
|
|
|
|
for( i=0; i<leftover+1; i++ )
|
|
text[start+i] = text[end+i];
|
|
|
|
/* printf( "final string: '%s'\n", text ); */
|
|
}
|
|
|
|
|
|
|
|
/************************************ GLUI_EditText::update_size() **********/
|
|
|
|
void GLUI_EditText::update_size( void )
|
|
{
|
|
int text_size, delta;
|
|
|
|
if ( NOT glui )
|
|
return;
|
|
|
|
text_size = string_width( name );
|
|
|
|
delta = 0;
|
|
if ( text_x_offset < text_size +2 )
|
|
delta = text_size+2-text_x_offset;
|
|
|
|
text_x_offset += delta;
|
|
/* w += delta; */
|
|
|
|
if ( data_type == GLUI_EDITTEXT_TEXT OR
|
|
data_type == GLUI_EDITTEXT_FLOAT) {
|
|
if ( w < text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH )
|
|
w = text_x_offset + GLUI_EDITTEXT_MIN_TEXT_WIDTH;
|
|
}
|
|
else if ( data_type == GLUI_EDITTEXT_INT ) {
|
|
if ( w < text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH )
|
|
w = text_x_offset + GLUI_EDITTEXT_MIN_INT_WIDTH;
|
|
}
|
|
}
|
|
|
|
|
|
/****************************** GLUI_EditText::set_text() **********/
|
|
|
|
void GLUI_EditText::set_text( char *new_text )
|
|
{
|
|
strncpy(text,new_text,sizeof(GLUI_String));
|
|
substring_start = 0;
|
|
substring_end = (int)strlen( text ) - 1;
|
|
insertion_pt = -1;
|
|
sel_start = 0;
|
|
sel_end = 0;
|
|
|
|
if ( can_draw() )
|
|
update_and_draw_text();
|
|
|
|
/** Update the spinner, if we have one **/
|
|
if ( spinner ) {
|
|
spinner->float_val = this->float_val;
|
|
spinner->int_val = this->int_val;
|
|
}
|
|
|
|
/*** Now update the live variable ***/
|
|
output_live(true);
|
|
}
|
|
|
|
|
|
/******************************* GLUI_EditText::set_float_val() ************/
|
|
|
|
void GLUI_EditText::set_float_val( float new_val )
|
|
{
|
|
if ( has_limits == GLUI_LIMIT_CLAMP ) {
|
|
/*** Clamp the new value to the existing limits ***/
|
|
|
|
CLAMP( new_val, float_low, float_high );
|
|
}
|
|
else if ( has_limits == GLUI_LIMIT_WRAP ) {
|
|
/*** Clamp the value cyclically to the limits - that is, if the
|
|
value exceeds the max, set it the the minimum, and conversely ***/
|
|
|
|
if ( new_val < float_low )
|
|
new_val = float_high;
|
|
if ( new_val > float_high )
|
|
new_val = float_low;
|
|
}
|
|
|
|
float_val = new_val;
|
|
int_val = (int) new_val; /* Mirror the value as an int, too */
|
|
|
|
set_numeric_text();
|
|
}
|
|
|
|
|
|
/********************************** GLUI_EditText::set_int_val() ************/
|
|
|
|
void GLUI_EditText::set_int_val( int new_val )
|
|
{
|
|
if ( has_limits == GLUI_LIMIT_CLAMP ) {
|
|
/*** Clamp the new value to the existing limits ***/
|
|
|
|
CLAMP( new_val, int_low, int_high );
|
|
}
|
|
else if ( has_limits == GLUI_LIMIT_WRAP ) {
|
|
/*** Clamp the value cyclically to the limits - that is, if the
|
|
value exceeds the max, set it the the minimum, and conversely ***/
|
|
|
|
if ( new_val < int_low )
|
|
new_val = int_high;
|
|
if ( new_val > int_high )
|
|
new_val = int_low;
|
|
}
|
|
|
|
int_val = new_val;
|
|
float_val = (float) new_val; /* We mirror the value as a float, too */
|
|
|
|
set_numeric_text();
|
|
}
|
|
|
|
|
|
/********************************* GLUI_EditText::set_float_limits() *********/
|
|
|
|
void GLUI_EditText::set_float_limits( float low, float high, int limit_type )
|
|
{
|
|
has_limits = limit_type;
|
|
float_low = low;
|
|
float_high = high;
|
|
|
|
if ( NOT IN_BOUNDS( float_val, float_low, float_high ))
|
|
set_float_val( float_low );
|
|
|
|
int_low = (int) float_low;
|
|
int_high = (int) float_high;
|
|
}
|
|
|
|
|
|
/*********************************** GLUI_EditText::set_int_limits() *********/
|
|
|
|
void GLUI_EditText::set_int_limits( int low, int high, int limit_type )
|
|
{
|
|
has_limits = limit_type;
|
|
int_low = low;
|
|
int_high = high;
|
|
|
|
if ( NOT IN_BOUNDS( int_val, int_low, int_high ))
|
|
set_int_val( int_low );
|
|
|
|
float_low = (float) int_low;
|
|
float_high = (float) int_high;
|
|
}
|
|
|
|
|
|
/************************************ GLUI_EditText::set_numeric_text() ******/
|
|
|
|
void GLUI_EditText::set_numeric_text( void )
|
|
{
|
|
char buf_float[200], buf_int[200];
|
|
int i, text_len;
|
|
|
|
if ( data_type == GLUI_EDITTEXT_FLOAT ) {
|
|
sprintf( buf_float, "%#g", float_val );
|
|
|
|
num_periods = 0;
|
|
text_len = (int)strlen( buf_float );
|
|
for ( i=0; i<text_len; i++ )
|
|
if ( buf_float[i] == '.' )
|
|
num_periods++;
|
|
|
|
/* Now remove trailing zeros */
|
|
if ( num_periods > 0 ) {
|
|
text_len = (int)strlen( buf_float );
|
|
for ( i=text_len-1; i>0; i-- ) {
|
|
if ( buf_float[i] == '0' AND buf_float[i-1] != '.' )
|
|
buf_float[i] = '\0';
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
set_text( buf_float );
|
|
}
|
|
else {
|
|
sprintf( buf_int, "%d", int_val );
|
|
|
|
set_text( buf_int );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*************************************** GLUI_EditText::dump() **************/
|
|
|
|
void GLUI_EditText::dump( FILE *out, char *name )
|
|
{
|
|
fprintf( out,
|
|
"%s (edittext@%p): ins_pt:%d subs:%d/%d sel:%d/%d len:%d\n",
|
|
name, this,
|
|
insertion_pt, substring_start, substring_end, sel_start, sel_end,
|
|
(int)strlen( text ));
|
|
}
|
|
|
|
|
|
/**************************************** GLUI_EditText::mouse_over() ********/
|
|
|
|
int GLUI_EditText::mouse_over( int state, int x, int y )
|
|
{
|
|
if ( state ) {
|
|
/* curr_cursor = GLUT_CURSOR_TEXT; */
|
|
glutSetCursor( GLUT_CURSOR_TEXT );
|
|
}
|
|
else {
|
|
/* printf( "OUT\n" ); */
|
|
glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
|
|
}
|
|
|
|
return true;
|
|
}
|