/* field.c */ /* * Field Widget - a single line type-in text field. */ #include #include #include #include #include #include "lui.h" #include "field.h" #define LMARGIN 2 static void copy_string( char *dst, char *src, int max ) { int i; for (i=0; itext) <= field->columns || strlen(field->text) >= field->len_limit) { /* whole string is visible, don't scroll */ field->scroll = 0; } else { /* scroll so cursor is visible */ if (field->curpos < field->scroll) { /* left */ field->scroll = field->curpos; } else if (field->curpos-field->scroll > field->columns) { /* right */ field->scroll = field->curpos - field->columns; } else { /* no change */ } } if (field->scroll==field->curpos && field->scroll>0) { field->scroll -= 1; } } void draw_field( LUI_FIELD *field ) { int x = LUI_Border; int y = LUI_Border; int texty; /* XFillRectangle( LUI_Display, field->window, LUI_GC_gray, x, y, field->width-2*LUI_Border, field->height-2*LUI_Border ); */ XFillRectangle( LUI_Display, field->window, LUI_GC_white, x, y, field->width-2*LUI_Border, field->height-2*LUI_Border ); texty = LUI_Border + (field->height - 2*LUI_Border - LUI_Font_height) / 2 + LUI_Font_yoff; assert( field->scroll <= strlen(field->text) ); XDrawString( LUI_Display, field->window, LUI_GC_black, x+LMARGIN, texty, field->text + field->scroll, strlen(field->text) - field->scroll ); LUI_DrawFrame( field->window, 0,0, field->width, field->height, LUI_Border, 0 ); if (field->editing) { /* draw cursor */ int dir, ascent, descent, width, height; XCharStruct overall; XTextExtents( LUI_Font, field->text + field->scroll, /* the text */ field->curpos - field->scroll, /* text length */ &dir, &ascent, &descent, &overall); width = overall.width; height = ascent + descent; x = LUI_Border + LMARGIN + width; y = texty - LUI_Font_yoff - 1; XDrawLine( LUI_Display, field->window, LUI_GC_black, x, y, x, y+height+2 ); XDrawLine( LUI_Display, field->window, LUI_GC_black, x+1, y, x+1, y+height+2 ); XDrawLine( LUI_Display, field->window, LUI_GC_black, x-1, y, x+2, y ); XDrawLine( LUI_Display, field->window, LUI_GC_black, x-1, y+height+2, x+2, y+height+2 ); } } /* * Set the current text of a field. */ void LUI_FieldSetText( LUI_FIELD *field, char *text ) { copy_string( field->text, text, MAX_FIELD ); field->text[MAX_FIELD-1] = 0; field->curpos = strlen( field->text ); compute_scroll( field ); draw_field( field ); } /* * Set the current text of a field as a double. */ void LUI_FieldSetDouble( LUI_FIELD *field, double x ) { sprintf( field->text, "%g", x ); field->curpos = strlen( field->text ); compute_scroll( field ); draw_field( field ); } void LUI_FieldSetNotDouble( LUI_FIELD *field, double x ) { sprintf( field->text, "%.3f", x ); field->curpos = strlen( field->text ); compute_scroll( field ); draw_field( field ); } /* * Set the current text of a field as an integer. */ void LUI_FieldSetInt( LUI_FIELD *field, int i ) { sprintf( field->text, "%d", i ); field->curpos = strlen( field->text ); compute_scroll( field ); draw_field( field ); } /* * Return the current contests of a field as a string. */ void LUI_FieldGetText( LUI_FIELD *field, char *text ) { copy_string( text, field->text, MAX_FIELD ); } /* * Return the current contents of a field as a double. */ double LUI_FieldGetDouble( LUI_FIELD *field ) { return atof( field->text ); } /* * Return the current contents of a field as an integer. */ int LUI_FieldGetInt( LUI_FIELD *field ) { return atoi( field->text ); } /* * Specify the callback for a field widget. It will be called whenever * the field's text has been modified. * Input: field - which field widget * callback - pointer to callback function declared as: * int callback( LUI_FIELD *field, char *text ) */ void LUI_FieldCallback( LUI_FIELD *field, int (* callback)() ) { field->callback = callback; field->context_index = context_index; } static void keypress( LUI_FIELD *field, XEvent *event ) { KeySym keysym; XComposeStatus compose; char buffer[100]; int len, count; if (!field->editing) return; count = XLookupString( &event->xkey, buffer, 100, &keysym, &compose ); len = strlen( field->text ); if (keysym==XK_Left) { if (field->curpos>0) { field->curpos--; } compute_scroll( field ); } else if (keysym==XK_Right) { if (field->curposcurpos++; } compute_scroll( field ); } else if (keysym==XK_BackSpace) { if (field->curpos>0) { char *ch = field->text + field->curpos - 1; while (*ch) { *ch = *(ch+1); ch++; } field->curpos--; field->modified = 1; if (field->scroll>0) { field->scroll--; } /* compute_scroll( field );*/ } } else if (keysym==XK_Delete) { if (field->curpos < len) { char *ch = field->text + field->curpos; while (*ch) { *ch = *(ch+1); ch++; } field->modified = 1; compute_scroll( field ); } } else if (keysym==XK_Return) { /* field->editing = 0;*/ field->modified = 0; if (field->callback) { (*field->callback)( field, field->text ); } } else if (keysym==XK_Tab) { if (field->warp_to) { field->editing = 0; field->modified = 0; if (field->callback) { (*field->callback)( field, field->text ); } XWarpPointer( LUI_Display, None, field->warp_to->window, 0,0, 0,0, event->xkey.x, event->xkey.y ); } } else if (count==1 && len < field->len_limit) { /* insert */ int i; /* char *ch = field->text + len; for (i=0;i<=len-field->curpos;i++) { *(ch+1) = *ch; ch--; } *ch = buffer[0]; */ for (i=len; i>=field->curpos; i--) { field->text[i+1] = field->text[i]; } field->text[field->curpos] = buffer[0]; field->curpos++; field->modified = 1; compute_scroll( field ); } draw_field( field ); } /* * This is called when the mouse button is clicked in the field. Use * the value of x (in pixels) to position the cursor. */ static void click( LUI_FIELD *field, int x ) { int len, pos; len = strlen( field->text ); field->curpos = len; for (pos=0;pos<=len;pos++) { int dir, ascent, descent, width; XCharStruct overall; XTextExtents( LUI_Font, field->text + field->scroll, pos, &dir, &ascent, &descent, &overall); width = overall.width; if (LUI_Border + LMARGIN + width > x) { if (pos>0) field->curpos = field->scroll + pos - 1; else field->curpos = field->scroll + 0; break; } } field->editing = 1; field->modified = 0; draw_field( field ); } static int field_process( LUI_FIELD *field, XEvent *event ) { switch (event->type) { case KeyPress: keypress( field, event ); break; case ButtonPress: click( field, event->xbutton.x ); break; case EnterNotify: field->editing = 1; field->modified = 0; draw_field( field ); break; case LeaveNotify: field->editing = 0; draw_field( field ); if (field->modified && field->callback) { (*field->callback)( field, field->text ); } field->modified = 0; break; case Expose: draw_field( field ); break; default: ; } return 1; } /* * Destroy a type-in field. */ void LUI_FieldDestroy( LUI_FIELD *field ) { LUI_EventRemove( field->window ); XDestroyWindow( LUI_Display, field->window ); free( field ); } LUI_FIELD *LUI_FieldCreate( Window parent, int x, int y, int width, int height ) { LUI_FIELD *field; LUI_LayoutCheck( &x, &y, &width, &height ); field = (LUI_FIELD *) malloc( sizeof(LUI_FIELD) ); if (!field) { return NULL; } field->window = XCreateSimpleWindow( LUI_Display, parent, x, y, width-2, height-2, 1, LUI_Color_black, LUI_Color_gray ); LUI_EventAdd2( field->window, KeyPressMask | ExposureMask | ButtonPressMask | EnterWindowMask | LeaveWindowMask, (LUI_FNCP) field_process, field ); XMapWindow( LUI_Display, field->window ); field->x = x; field->y = y; field->width = width-2; field->height = height-2; field->text[0] = 0; field->curpos = 0; field->columns = (width-2) / LUI_Font_width - 1; field->scroll = 0; field->editing = 0; field->modified = 0; field->callback = NULL; field->warp_to = NULL; field->len_limit = 10000; LUI_AddWidgetToWindow( parent, field, (LUI_FNCP) LUI_FieldDestroy ); return field; } /* * Link two field widgets together so that pressing TAB in one moves the * input focus to the next field. */ void LUI_FieldLink( LUI_FIELD *from, LUI_FIELD *to ) { from->warp_to = to; }