/* * XMapEdit, the XPilot Map Editor. Copyright (C) 1993 by * * Aaron Averill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Modifications to XMapEdit * 1996: * Robert Templeman * 1997: * William Docter * * $Id: T_Form.c,v 5.0 2001/04/07 20:01:00 dik Exp $ */ #include "T_Toolkit.h" T_Form_t *T_Form = NULL; /***************************************************************************/ /* T_FormEventCheck */ /* Arguments : */ /* report */ /* Purpose : Called from the main event check loop in application. */ /***************************************************************************/ void T_FormEventCheck(XEvent *report) { switch (report->type) { case Expose: if (report->xexpose.count == 0) { T_FormExpose(report); } break; case ButtonPress: T_FormButtonPress(report); break; case KeyPress: T_FormKeyPress(report); break; } } /***************************************************************************/ /* T_FormExpose */ /* Arguments : */ /* report */ /* Purpose : Handle an exposure for window win. Draw all items in form. */ /***************************************************************************/ void T_FormExpose(XEvent *report) { Window win; T_Form_t *form; T_Field_t *field; char *label; int multi,w,h,i,j; win = report->xexpose.window; form = (*(SeekForm(win,0)) ); if (form == NULL) return; field = form->field; while (field != NULL) { if (field->active != INACTIVE ) { switch (field->type) { case T_BUTTON: case T_TEXT_BUTTON: case T_HOLD_BUTTON: T_DrawTextButton(form->window,field->x,field->y,field->width, field->height,RAISED,field->label); break; case T_MULTI_BUTTON: label = malloc(strlen(field->label)+1); strcpy(label,field->label); label = strtok(label,";"); multi = 1; w = (field->width) / (field->x2); h = (field->height) / (field->y2); for (i=0;iy2;i++) { for (j=0;jx2;j++) { if (multi == (*(field->intvar)) ) { T_DrawTextButton(form->window,j*w+field->x, i*h+field->y,w-1,h-1,LOWERED,label); } else { T_DrawTextButton(form->window,j*w+field->x, i*h+field->y,w-1,h-1,RAISED,label); } multi++; if (label != NULL) { label = strtok(NULL,";"); } } } break; case T_TEXT: T_DrawString(form->window,field->x,field->y,field->width, field->height,BKGR,field->label,field->x2,CROP_RIGHT,-1); break; case T_STRING_ENTRY: T_DrawEntryField(form, field); if (field->label != NULL) { w = XTextWidth(T_Font,field->label,strlen(field->label)); i = field->x+field->x2; j = field->y+field->y2; T_DrawString(form->window,i,j,w,field->height,BKGR, field->label,JUSTIFY_LEFT,CROP_RIGHT,-1); } break; } } field = field->next; } } /***************************************************************************/ /* T_FormButtonPress */ /* Arguments : */ /* eventreport */ /* Purpose : Handle button press. */ /***************************************************************************/ void T_FormButtonPress(XEvent *report) { Window win, root, child; int x,y,rootx,rooty; T_Form_t *form; T_Field_t *field; unsigned int keysbuttons, btn; int multi,w,h,x2,y2,count=0; XEvent event; win = report->xbutton.window; x = report->xbutton.x; y = report->xbutton.y; btn = report->xbutton.button; form = (*(SeekForm(win,0)) ); if (form == NULL) return; field = form->field; while (field != NULL) { if ( (x>field->x) && (y>field->y) && (x<(field->x+field->width)) && (y<(field->y+field->height)) && (field->active == ACTIVE) ) { switch (field->type) { case T_BUTTON: case T_TEXT_BUTTON: case T_HOLD_BUTTON: T_DrawTextButton(form->window,field->x,field->y,field->width, field->height,LOWERED,field->label); break; case T_MULTI_BUTTON: multi = (y-field->y)*field->y2/field->height; multi *= field->x2; multi += (x-field->x)*field->x2/field->width; if ( ((multi+1) != (*(field->intvar))) || (field->null) ) { w = field->width / field->x2; h = field->height / field->y2; y2 = ((*(field->intvar))-1) / field->x2; x2 = ((*(field->intvar))-1) - (y2*field->x2); if ((*(field->intvar)) != 0) { T_PopButton(form->window,x2*w+field->x,y2*h+field->y, w-1, h-1, RAISED); } y2 = multi / field->x2; x2 = multi - (y2*field->x2); if ( (multi+1) != (*(field->intvar)) ) { T_PopButton(form->window,x2*w+field->x,y2*h+field->y, w-1, h-1, LOWERED); (*(field->intvar)) = multi+1; } else { (*(field->intvar)) = 0; } } return; case T_STRING_ENTRY: T_SetEntryField(form,field,x-field->x-2); return; } switch (field->type) { case T_SCROLL_UNBOUND: case T_BUTTON: case T_TEXT_BUTTON: x2 = -1; y2 = -1; event = *report; while (event.type != ButtonRelease) { if ( (x != x2) || (y != y2) ) { count++; if ( (field->type == T_SCROLL_UNBOUND) ) { CallFieldHandler(form,field,x,y,btn,count, field->handler); } x2 = x; y2 = y; } XCheckMaskEvent(display,(long)(ButtonReleaseMask), &event); if (!XQueryPointer(display, event.xmotion.window, &root, &child, &rootx, &rooty, &x, &y, &keysbuttons)) { event.type = ButtonRelease; } } break; case T_HOLD_BUTTON: event = *report; while (event.type != ButtonRelease) { count++; CallFieldHandler(form,field,x,y,btn,count,field->handler); if (XCheckMaskEvent(display,(long)(ButtonReleaseMask), &event) == True) { event.type = ButtonRelease; } } break; } switch (field->type) { case T_BUTTON: case T_TEXT_BUTTON: case T_HOLD_BUTTON: T_DrawTextButton(form->window,field->x,field->y,field->width, field->height,RAISED,field->label); if ((x>field->x) && (y>field->y) && (x<(field->x+field->width)) && (y<(field->y+field->height)) ) { CallFieldHandler(form, field, x, y, btn, 0, field->handler); } break; case T_STRING_ENTRY: case T_SCROLL_UNBOUND: CallFieldHandler(form, field, x, y, btn, 0, field->handler); break; } return; } else { field = field->next; } } } /***************************************************************************/ /* T_FormKeyPress */ /* Arguments : */ /* report */ /* Purpose : Handle Keypresses. */ /***************************************************************************/ void T_FormKeyPress(XEvent *report) { T_Form_t *form; char buffer[2]; int bufsize=1; KeySym keysym; XComposeStatus compose; int count; char *tmpstr, *tmpstr2; form = (*(SeekForm(report->xkey.window,0)) ); if (form == NULL) return; if (form->entry == NULL) return; count = XLookupString(&report->xkey, buffer, bufsize, &keysym, &compose); buffer[bufsize] = '\0'; if ((keysym == XK_Return) || (keysym == XK_KP_Enter ) || (keysym == XK_Linefeed)) { T_SetEntryField(form,0,0); return; } else if (((keysym >= XK_KP_Space) && (keysym <= XK_KP_9)) || ((keysym >= XK_space) && (keysym <= XK_asciitilde))) { if (strlen(form->entry->charvar) < form->entry->charvar_length) { tmpstr = malloc(strlen(form->entry->charvar)+2); tmpstr[0] = (char) NULL; tmpstr2 = form->entry->charvar; tmpstr2 += form->entry_cursor; strncat(tmpstr, form->entry->charvar,form->entry_cursor); strcat(tmpstr,buffer); strcat(tmpstr,tmpstr2); strcpy(form->entry->charvar,tmpstr); free(tmpstr); form->entry_cursor++; } } else if ((keysym == XK_BackSpace) || (keysym == XK_Delete)) { if (form->entry_cursor > 0) { tmpstr = malloc(strlen(form->entry->charvar)); tmpstr[0] = (char) NULL; tmpstr2 = form->entry->charvar; tmpstr2 += form->entry_cursor; strncat(tmpstr,form->entry->charvar,form->entry_cursor-1); strcpy(form->entry->charvar,tmpstr); strcat(form->entry->charvar,tmpstr2); free(tmpstr); form->entry_cursor--; } } else if (keysym == XK_Home) { form->entry_cursor = 0; } else if (keysym == XK_Right) { if (form->entry_cursor < strlen(form->entry->charvar) ) { form->entry_cursor++; } else { return; } } else if (keysym == XK_Left) { if (form->entry_cursor > 0) { form->entry_cursor--; } else { return; } } else { return; } if ((form->entry_cursor-1) < form->entry_pos ) { if (form->entry_pos != 0) { form->entry_pos = form->entry_cursor-1; if (form->entry_pos < 0) { form->entry_pos = 0; } } } tmpstr = form->entry->charvar; tmpstr += form->entry_pos; count = form->entry_cursor - form->entry_pos; while ( XTextWidth(T_Font,tmpstr,count) > form->entry->width-10) { tmpstr++; count--; form->entry_pos++; } T_DrawEntryField(form, form->entry); } /***************************************************************************/ /* CallFieldHandler */ /* Arguments : */ /* handler */ /* Purpose : Set up the HandlerInfo structure and call handler. */ /***************************************************************************/ void CallFieldHandler(T_Form_t *form, T_Field_t *field, int x, int y, unsigned int button, int count, int (*handler)()) { HandlerInfo info; if (handler == NULL) return; info.form = form; info.field = field; info.x = x; info.y = y; info.count = count; info.button = button; handler(info); } /***************************************************************************/ /* T_FormClear */ /* Arguments : */ /* win */ /* Purpose : Deallocate all resources for a form */ /***************************************************************************/ void T_FormClear(Window win) { T_Form_t **form; T_Field_t *field, *delfield; /* traverse until we find the form correct window */ form = SeekForm(win,0); if ( (*form) == NULL ) return; /* traverse fields and free as we go */ field = (*form)->field; while (field != NULL) { delfield = field->next; free(field); field = delfield; } (*form)->field = NULL; (*form)->entry = NULL; (*form)->entry_cursor = (*form)->entry_pos = 0; if ((*form)->entry_restore) free((*form)->entry_restore); (*form)->entry_restore = (char *) NULL; } /***************************************************************************/ /* T_FormCloseWindow */ /* Arguments : */ /* win */ /* Purpose : Deallocate all resources for a form and unmap window. */ /***************************************************************************/ void T_FormCloseWindow(Window win) { T_Form_t **form, *delform; T_Field_t *field, *delfield; /* traverse until we find the form correct window */ form = SeekForm(win,0); if ( (*form) == NULL ) return; XDestroyWindow(display,win); delform = (*form); (*form) = (*form)->next; /* traverse fields and free as we go */ field = delform->field; while (field != NULL) { delfield = field->next; free(field); field = delfield; } free(delform); } /***************************************************************************/ /* SeekForm */ /* Arguments : */ /* win */ /* add */ /* Purpose : Seek to the form of the specified window. If it is not found, */ /* add a blank form if add is set. Return address of pointer */ /* to form. */ /***************************************************************************/ T_Form_t **SeekForm(Window win, short add) { T_Form_t **form; /* traverse until we find the form with the specified window */ form = &T_Form; while ( ( (*form) != NULL) && ((*form)->window != win ) ) { form = &((*form)->next); } /* if we are at the end add a window */ if ( ((*form) == NULL) && (add) ) { (*form) = (T_Form_t *) malloc(sizeof(T_Form_t)); (*form)->window = win; (*form)->field = NULL; (*form)->entry = NULL; (*form)->entry_cursor = (*form)->entry_pos = 0; (*form)->entry_restore = NULL; (*form)->next = NULL; } return form; } /***************************************************************************/ /* ChangeField */ /* Arguments : */ /* Purpose : Change or add a field with the specified information. */ /***************************************************************************/ void ChangeField(Window win, char *name, char *label, short type, short active, short x, short y, short width, short height, short x2, short y2, int (*handler)(), int *intvar, char *charvar, int charvar_length, short null) { T_Form_t **form; T_Field_t **field, *next = NULL; if ( (win == 0) || (name == NULL) ) return; form = SeekForm(win,1); field = &((*form)->field); while ( ((*field) != NULL) && (strcmp( (*field)->name,name)) ) { field = &((*field)->next); } if ( (*field) != NULL ) { next = (*field)->next; free(*field); } (*field) = (T_Field_t *) malloc(sizeof(T_Field_t)); (*field)->name = malloc(strlen(name)+1); strcpy((*field)->name, name); if ( label != NULL ) { (*field)->label = malloc(strlen(label)+1); strcpy((*field)->label, label); } else { (*field)->label = NULL; } (*field)->type = type; (*field)->active = active; (*field)->x = x; (*field)->y = y; (*field)->width = width; (*field)->height = height; (*field)->x2 = x2; (*field)->y2 = y2; (*field)->handler = handler; (*field)->intvar = intvar; (*field)->charvar = charvar; (*field)->charvar_length = charvar_length; (*field)->null = null; (*field)->next = next; } /***************************************************************************/ /* T_FormHoldButton */ /* Arguments : */ /* win */ /* name */ /* x */ /* y */ /* width */ /* height */ /* label */ /* handler */ /* Purpose : Add a button to form of window win. */ /***************************************************************************/ void T_FormHoldButton(Window win, char *name, short x, short y, short width, short height, char *label, int (*handler)()) { ChangeField(win,name,label,T_HOLD_BUTTON,ACTIVE,x,y,width,height,0,0, handler,(int *) NULL,(char *) NULL,0,0); } /***************************************************************************/ /* T_FormButton */ /* Arguments : */ /* win */ /* name */ /* x */ /* y */ /* width */ /* height */ /* label */ /* handler */ /* Purpose : Add a button to form of window win. */ /***************************************************************************/ void T_FormButton(Window win, char *name, short x, short y, short width, short height, char *label, int (*handler)()) { ChangeField(win,name,label,T_BUTTON,ACTIVE,x,y,width,height,0,0, handler,(int *) NULL,(char *) NULL,0,0); } /***************************************************************************/ /* T_FormMultiButton */ /* Arguments : */ /* win */ /* name */ /* x */ /* y */ /* width */ /* height */ /* x2 */ /* y2 */ /* label */ /* intvar */ /* null */ /* Purpose : Add a button to form of window win. */ /***************************************************************************/ void T_FormMultiButton(Window win, char *name, short x, short y, short width, short height, short x2, short y2, char *label, int *intvar, short null) { ChangeField(win,name,label,T_MULTI_BUTTON,ACTIVE,x,y,width,height,x2,y2, NULL,intvar,(char *) NULL,0,null); } /***************************************************************************/ /* T_FormScrollArea */ /* Arguments : */ /* win */ /* name */ /* type */ /* x */ /* y */ /* width */ /* height */ /* handler */ /* Purpose : Add a button to form of window win. */ /***************************************************************************/ void T_FormScrollArea(Window win, char *name, short type, short x, short y, short width, short height, int (*handler)()) { ChangeField(win,name,NULL,type,ACTIVE,x,y,width,height,0,0, handler,(int *) NULL,(char *) NULL,0,0); } /***************************************************************************/ /* T_FormText */ /* Arguments : */ /* win */ /* name */ /* x */ /* y */ /* width */ /* height */ /* label */ /* justify */ /* Purpose : Add a button to form of window win. */ /***************************************************************************/ void T_FormText(Window win, char *name, short x, short y, short width, short height, char *label, short justify) { ChangeField(win,name,label,T_TEXT,ACTIVE,x,y,width,height,justify,0, NULL,(int *) NULL,(char *) NULL,0,0); } /***************************************************************************/ /* T_FormStringEntry */ /* Arguments : */ /* win */ /* name */ /* x */ /* y */ /* width */ /* height */ /* x2 */ /* y2 */ /* label */ /* justify */ /* Purpose : Add a button to form of window win. */ /***************************************************************************/ void T_FormStringEntry(Window win, char *name, short x, short y, short width, short height, short x2, short y2, char *label, char *charvar, int charvar_length, int (*handler)()) { ChangeField(win,name,label,T_STRING_ENTRY,ACTIVE,x,y,width,height,x2,y2, handler, (int *) NULL, charvar, charvar_length, 0); } /***************************************************************************/ /* T_DrawEntryField */ /* Arguments : */ /* Purpose : Deallocate all resources for a form and unmap window. */ /***************************************************************************/ void T_DrawEntryField (T_Form_t *form, T_Field_t *field) { char *tmpstr; if (field == (T_Field_t *) form->entry ) { tmpstr = field->charvar; tmpstr += form->entry_pos; #ifdef MONO T_DrawButton(form->window,field->x,field->y,field->width, field->height,LOWERED,1); #else T_DrawButton(form->window,field->x,field->y,field->width, field->height,RAISED,1); #endif T_DrawString(form->window,field->x+5,field->y,field->width-10, field->height,BKGR,tmpstr,JUSTIFY_LEFT,CROP_RIGHT, form->entry_cursor - form->entry_pos); } else { #ifdef MONO T_DrawButton(form->window,field->x,field->y,field->width, field->height,RAISED,1); #else T_DrawButton(form->window,field->x,field->y,field->width, field->height,LOWERED,1); #endif T_DrawString(form->window,field->x+5,field->y,field->width-10, field->height,BKGR,field->charvar,JUSTIFY_LEFT,CROP_RIGHT,-1); } } /***************************************************************************/ /* T_SetEntryField */ /* Arguments : */ /* form */ /* field */ /* x */ /* Purpose : Set global variables that point to the current text entry */ /* field. Popup the old text entry field and execute the */ /* function if it is not NULL. */ /***************************************************************************/ void T_SetEntryField(T_Form_t *form, T_Field_t *field, int x) { int length; char *tmpstr, *charvar; if (field == (T_Field_t *) form->entry) { tmpstr = field->charvar; tmpstr += form->entry_pos; length = strlen(tmpstr); while( (x < XTextWidth(T_Font,tmpstr,length)) && (length > 0) ) length--; form->entry_cursor = form->entry_pos + length; T_DrawEntryField(form,(T_Field_t *) form->entry); } else { if ( form->entry != NULL ) { /* BG hackfix: remember what our window is. */ Window form_window = form->window; charvar = form->entry->charvar; CallFieldHandler(form,(T_Field_t *) form->entry, 0,0,0,0, form->entry->handler); /* BG hackfix: * If this form was a popup and if the popup was destroyed by * the form entry handler then we get out of here immediately. */ if (*SeekForm(form_window,0) != form) { return; } form->entry = NULL; T_FormRedrawEntryField(charvar); free(form->entry_restore); } form->entry = field; if ( form->entry == NULL ) return; form->entry_restore = malloc (strlen(field->charvar) +1); strcpy(form->entry_restore, field->charvar); length = strlen( form->entry->charvar ); while( (xentry->charvar,length)) && (length>0)) { length--; } form->entry_cursor = length; form->entry_pos = 0; T_DrawEntryField(form,field); } } /***************************************************************************/ /* T_FormRedrawEntryField */ /* Arguments : */ /* charvar */ /* Purpose : Redraw fields containing charvar. */ /***************************************************************************/ void T_FormRedrawEntryField(char *charvar) { T_Form_t *form; T_Field_t *field; form = T_Form; while ( form != NULL ) { field = form->field; while ( field != NULL ) { if ( (field->type == T_STRING_ENTRY) && (field->charvar == charvar) && (field->active != INACTIVE) ) { T_DrawEntryField(form,field); } field = field->next; } form = form->next; } }