argv@island.uu.net (Dan Heller) (04/11/89)
Submitted-by: David Harrison <davidh@ic.berkeley.edu> Posting-number: Volume 3, Issue 72 Archive-name: xgraph/part03 if `test ! -s ./xgraph-11/xtb/xtb.c` then echo "writing ./xgraph-11/xtb/xtb.c" cat > ./xgraph-11/xtb/xtb.c << '\End\Of\Shar\' /* * Mini-Toolbox * * David Harrison * University of California, Berkeley * 1988, 1989 * * This file contains routines which implement simple display widgets * which can be used to construct simple dialog boxes. * A mini-toolbox has been written here (overkill but I didn't * want to use any of the standards yet -- they are too unstable). */ #include <X11/Xlib.h> #include <X11/Xutil.h> #include "xtb.h" #define MAXKEYS 10 #ifdef __STDC__ #define FNPTR(fname, rtn, args) rtn (*fname)args #include <stdarg.h> #define VARARGS(func, rtn, args) rtn func args #else #define FNPTR(fname, rtn, args) rtn (*fname)() #include <varargs.h> #define VARARGS(func, rtn, args) /*VARARGS*/ rtn func(va_alist) va_dcl #endif typedef struct h_info { FNPTR(func, xtb_hret, (XEvent *evt, xtb_data info)); /* Function to call */ xtb_data info; /* Additional info */ }; static Display *t_disp; /* Display */ static int t_scrn; /* Screen */ static unsigned long norm_pix; /* Foreground color */ static unsigned long back_pix; /* Background color */ static XFontStruct *norm_font; /* Normal font */ extern char *malloc(); #define STRDUP(str) (strcpy(malloc((unsigned) (strlen(str)+1)), (str))) extern char *strcpy(); extern void free(); void xtb_init(disp, scrn, foreground, background, font) Display *disp; /* Display */ int scrn; /* Screen number */ unsigned long foreground; /* Foreground color */ unsigned long background; /* Background color */ XFontStruct *font; /* Normal font */ /* * Sets default parameters used by the mini-toolbox. */ { t_disp = disp; t_scrn = scrn; norm_pix = foreground; back_pix = background; norm_font = font; } static GC set_gc(win, fg, bg, font) Window win; /* For creating GC */ unsigned long fg; /* Foreground pixel */ unsigned long bg; /* Background pixel */ Font font; /* Font */ /* * Sets and returns the fields listed above in a global graphics context. * If graphics context does not exist, it is created. */ { static GC t_gc = (GC) 0; XGCValues gcvals; unsigned long gcmask; gcvals.foreground = fg; gcvals.background = bg; gcvals.font = font; gcmask = GCForeground | GCBackground | GCFont; if (t_gc == (GC) 0) { t_gc = XCreateGC(t_disp, win, gcmask, &gcvals); } else { XChangeGC(t_disp, t_gc, gcmask, &gcvals); } return t_gc; } static XContext h_context = (XContext) 0; void xtb_register(win, func, info) Window win; FNPTR( func, xtb_hret, (XEvent *evt, xtb_data info) ); xtb_data info; /* * Associates the event handling function `func' with the window * `win'. Additional information `info' will be passed to `func'. * The routine should return one of the return codes given above. */ { struct h_info *new_info; if (h_context == (XContext) 0) { h_context = XUniqueContext(); } new_info = (struct h_info *) malloc(sizeof(struct h_info)); new_info->func = func; new_info->info = info; XSaveContext(t_disp, win, h_context, (caddr_t) new_info); } xtb_data xtb_lookup(win) Window win; /* * Returns the associated data with window `win'. */ { xtb_data data; if (!XFindContext(t_disp, win, h_context, &data)) { return ((struct h_info *) data)->info; } else { return (xtb_data) 0; } } xtb_hret xtb_dispatch(evt) XEvent *evt; /* * Dispatches an event to a handler if its ours. Returns one of * the return codes given above (XTB_NOTDEF, XTB_HANDLED, or XTB_STOP). */ { struct h_info *info; if (!XFindContext(t_disp, evt->xany.window, h_context, (caddr_t *) &info)) { if (info->func) return (*info->func)(evt, info->info); else return XTB_NOTDEF; } else return XTB_NOTDEF; } int xtb_unregister(win, info) Window win; xtb_data *info; /* * Removes `win' from the dialog association table. `info' is * returned to allow the user to delete it (if desired). Returns * a non-zero status if the association was found and properly deleted. */ { struct h_info *hi; if (!XFindContext(t_disp, win, h_context, (caddr_t *) &hi)) { (void) XDeleteContext(t_disp, win, h_context); *info = hi->info; free((char *) hi); return 1; } else return 0; } #define BT_HPAD 3 #define BT_VPAD 2 #define BT_LPAD 3 #define BT_BRDR 1 typedef struct b_info { FNPTR( func, xtb_hret, (Window win, int state, xtb_data val) ); /* Function to call */ char *text; /* Text of button */ int flag; /* State of button */ int line_y, line_w; /* Entry/Exit line */ xtb_data val; /* User defined info */ }; static void bt_draw(win, ri) Window win; struct b_info *ri; /* * Draws a button window */ { if (ri->flag) { XDrawImageString(t_disp, win, set_gc(win, back_pix, norm_pix, norm_font->fid), BT_HPAD, BT_VPAD+norm_font->ascent, ri->text, strlen(ri->text)); } else { XDrawImageString(t_disp, win, set_gc(win, norm_pix, back_pix, norm_font->fid), BT_HPAD, BT_VPAD+norm_font->ascent, ri->text, strlen(ri->text)); } } static void bt_line(win, ri, pix) Window win; struct b_info *ri; unsigned long pix; /* * Draws a status line beneath the text to indicate the * user has moved into the button. */ { XDrawLine(t_disp, win, set_gc(win, pix, back_pix, norm_font->fid), BT_HPAD, ri->line_y, BT_HPAD+ri->line_w, ri->line_y); } static xtb_hret bt_h(evt, info) XEvent *evt; xtb_data info; /* * Handles button events. */ { Window win = evt->xany.window; struct b_info *ri = (struct b_info *) info; xtb_hret rtn; switch (evt->type) { case Expose: bt_draw(win, ri); rtn = XTB_HANDLED; break; case EnterNotify: bt_line(win, ri, norm_pix); rtn = XTB_HANDLED; break; case LeaveNotify: bt_line(win, ri, back_pix); rtn = XTB_HANDLED; break; case ButtonPress: /* Nothing - just wait for button up */ break; case ButtonRelease: rtn = (*ri->func)(win, ri->flag, ri->val); break; default: rtn = XTB_NOTDEF; } return rtn; } void xtb_bt_new(win, text, func, val, frame) Window win; /* Parent window */ char *text; /* Text in button */ FNPTR( func, xtb_hret, (Window, int, xtb_data) ); /* Callback */ xtb_data val; /* User data */ xtb_frame *frame; /* Size (RETURN) */ /* * Makes a new button under `win' with the text `text'. The * window, size, and position of the button are returned in `frame'. * The initial position is always (0, 0). When the * button is pressed, `func' will be called with the button * window, the current state of the button, and `val'. * It is up to `func' to change the state of the button (if desired). * The routine should return XTB_HANDLED normally and XTB_STOP if the * dialog should stop. The window will be automatically mapped. */ { XCharStruct bb; struct b_info *info; int dir, ascent, descent; XTextExtents(norm_font, text, strlen(text), &dir, &ascent, &descent, &bb); frame->width = bb.width + 2*BT_HPAD; frame->height = norm_font->ascent + norm_font->descent + BT_VPAD + BT_LPAD; frame->x_loc = frame->y_loc = 0; frame->win = XCreateSimpleWindow(t_disp, win, frame->x_loc, frame->y_loc, frame->width, frame->height, BT_BRDR, norm_pix, back_pix); XSelectInput(t_disp, frame->win, ExposureMask| ButtonPressMask|ButtonReleaseMask| EnterWindowMask|LeaveWindowMask); info = (struct b_info *) malloc(sizeof(struct b_info)); info->func = func; info->text = STRDUP(text); info->flag = 0; info->val = val; info->line_y = frame->height - 2; info->line_w = frame->width - 2*BT_HPAD; xtb_register(frame->win, bt_h, (xtb_data) info); XMapWindow(t_disp, frame->win); frame->width += (2*BT_BRDR); frame->height += (2*BT_BRDR); } int xtb_bt_get(win, stuff) Window win; xtb_data *stuff; /* * Returns the state of button `win'. If provided, the button * specific info is returned in `info'. */ { struct b_info *info = (struct b_info *) xtb_lookup(win); if (stuff) *stuff = info->val; return info->flag; } int xtb_bt_set(win, val, stuff) Window win; int val; xtb_data stuff; /* * Changes the value of a button and returns the new state. * The button is drawn. If set, the button specific info * will be set to `info'. This doesn't allow you to set * the state to zero, but that may not be important. The * change in button appearance will be immediate. */ { struct b_info *info = (struct b_info *) xtb_lookup(win); info->flag = (val != 0); if (stuff) info->val = stuff; bt_draw(win, info); XFlush(t_disp); return info->flag; } void xtb_bt_del(win, info) Window win; xtb_data *info; /* * Deletes the button `win' and returns the user defined information * in `info' for destruction. */ { struct b_info *bi; if (xtb_unregister(win, (xtb_data *) &bi)) { *info = bi->val; free((char *) bi->text); free((char *) bi); XDestroyWindow(t_disp, win); } } #define BR_XPAD 2 #define BR_YPAD 2 #define BR_INTER 2 typedef struct br_info { Window main_win; /* Main button row */ int which_one; /* Which button is on */ int btn_cnt; /* How many buttons */ FNPTR( func, xtb_hret, (Window win, int prev, int this, xtb_data val) ); xtb_data val; /* User data */ Window *btns; /* Button windows */ }; /*ARGSUSED*/ static xtb_hret br_h(win, val, info) Window win; int val; xtb_data info; /* * This handles events for button rows. When a button is pressed, * it turns off the button selected in `which_one' and turns itself * on. */ { struct br_info *real_info = (struct br_info *) info; int i, prev; prev = real_info->which_one; if ((prev >= 0) && (prev < real_info->btn_cnt)) { (void) xtb_bt_set(real_info->btns[prev], 0, (xtb_data) 0); } for (i = 0; i < real_info->btn_cnt; i++) { if (win == real_info->btns[i]) { real_info->which_one = i; break; } } (void) xtb_bt_set(win, 1, (xtb_data) 0); /* Callback */ if (real_info->func) { return (*real_info->func)(real_info->main_win, prev, real_info->which_one, real_info->val); } else { return XTB_HANDLED; } } void xtb_br_new(win, cnt, lbls, init, func, val, frame) Window win; /* Parent window */ int cnt; /* Count of buttons */ char *lbls[]; /* Button labels */ int init; /* Initial button */ FNPTR( func, xtb_hret, (Window, int, int, xtb_data) ); /* Callback */ xtb_data val; /* User data */ xtb_frame *frame; /* Returned size */ /* * This routine makes a new row of buttons in the window `win' * and returns a frame containing all of these buttons. These * buttons are designed so that only one of them will be active * at a time. Initially, button `init' will be activated (if * init is less than zero, none will be initially activated). * Whenever a button is pushed, `func' will be called with the * button row window, the index of the previous button (-1 if * none), the index of the current button, and the user data, `val'. * The function is optional (if zero, no function will be called). * The size of the row is returned in `frame'. The window * will be automatically mapped. Initially, the window containing * the buttons will be placed at 0,0 in the parent window. */ { struct br_info *info; xtb_frame sub_frame; int i, x, y; frame->width = frame->height = 0; frame->x_loc = frame->y_loc = 0; frame->win = XCreateSimpleWindow(t_disp, win, 0, 0, 1, 1, 0, back_pix, back_pix); info = (struct br_info *) malloc(sizeof(struct br_info)); info->main_win = frame->win; info->btns = (Window *) malloc((unsigned) (sizeof(Window) * cnt)); info->btn_cnt = cnt; info->which_one = init; info->func = func; info->val = val; /* the handler is used simply to get information out */ xtb_register(frame->win, (xtb_hret (*)()) 0, (xtb_data) info); x = BR_XPAD; y = BR_YPAD; for (i = 0; i < cnt; i++) { xtb_bt_new(frame->win, lbls[i], br_h, (xtb_data) info, &sub_frame); info->btns[i] = sub_frame.win; XMoveWindow(t_disp, info->btns[i], x, y); x += (BR_INTER + sub_frame.width); if (sub_frame.height > frame->height) frame->height = sub_frame.height; if (i == init) (void) xtb_bt_set(info->btns[i], 1, (xtb_data) 0); } frame->width = x - BR_INTER + BR_XPAD; frame->height += (2 * BR_YPAD); XResizeWindow(t_disp, frame->win, frame->width, frame->height); XMapWindow(t_disp, frame->win); } int xtb_br_get(win) Window win; /* * This routine returns the index of the currently selected item of * the button row given by the window `win'. Note: no checking * is done to make sure `win' is a button row. */ { struct br_info *info = (struct br_info *) xtb_lookup(win); return info->which_one; } void xtb_br_del(win) Window win; /* * Deletes a button row. All resources are reclaimed. */ { struct br_info *info; int i; if (xtb_unregister(win, (xtb_data *) &info)) { for (i = 0; i < info->btn_cnt; i++) { xtb_bt_del(info->btns[i], (xtb_data *) &info); } free((char *) info->btns); free((char *) info); XDestroyWindow(t_disp, win); } } /* Text widget */ #define TO_HPAD 1 #define TO_VPAD 1 typedef struct to_info { char *text; /* Text to display */ XFontStruct *ft; /* Font to use */ }; static void to_draw(win, ri) Window win; struct to_info *ri; /* * Draws the text for a widget */ { XDrawImageString(t_disp, win, set_gc(win, norm_pix, back_pix, ri->ft->fid), TO_HPAD, TO_VPAD+ri->ft->ascent, ri->text, strlen(ri->text)); } static xtb_hret to_h(evt, info) XEvent *evt; xtb_data info; /* * Handles text widget events */ { Window win = evt->xany.window; struct to_info *ri = (struct to_info *) info; switch (evt->type) { case Expose: to_draw(win, ri); return XTB_HANDLED; default: return XTB_NOTDEF; } } void xtb_to_new(win, text, ft, frame) Window win; /* Parent window */ char *text; /* Text */ XFontStruct *ft; /* Font to use */ xtb_frame *frame; /* Returned size */ /* * Makes a new text widget under `win' with the text `text'. * The size of the widget is returned in `w' and `h'. The * window is created and mapped at 0,0 in `win'. The font * used for the text is given in `ft'. */ { struct to_info *info; XCharStruct bb; int dir, ascent, descent; XTextExtents(ft, text, strlen(text), &dir, &ascent, &descent, &bb); frame->width = bb.width + 2*TO_HPAD; frame->height = bb.ascent + bb.descent + (2 * TO_VPAD); frame->x_loc = frame->y_loc = 0; frame->win = XCreateSimpleWindow(t_disp, win, 0, 0, frame->width, frame->height, 0, back_pix, back_pix); XSelectInput(t_disp, frame->win, ExposureMask); info = (struct to_info *) malloc(sizeof(struct to_info)); info->text = STRDUP(text); info->ft = ft; xtb_register(frame->win, to_h, (xtb_data) info); XMapWindow(t_disp, frame->win); } void xtb_to_del(win) Window win; /* * Deletes an output only text widget. */ { struct to_info *info; if (xtb_unregister(win, (xtb_data *) &info)) { free((char *) info->text); free((char *) info); XDestroyWindow(t_disp, win); } } /* * Input text widget */ #define TI_HPAD 2 #define TI_VPAD 2 #define TI_LPAD 3 #define TI_BRDR 2 #define TI_CRSP 1 typedef struct ti_info { FNPTR( func, xtb_hret, (Window win, int ch, char *textcopy, xtb_data *val) ); /* Function to call */ int maxlen; /* Maximum characters */ int curidx; /* Current index pos */ int curxval; /* Current draw loc */ char text[MAXCHBUF]; /* Current text array */ int line_y, line_w; /* Entry/Exit line */ int focus_flag; /* If on, we have focus */ xtb_data val; /* User info */ }; static int text_width(font, str, len) XFontStruct *font; /* What font */ char *str; /* Character array */ int len; /* Length of array */ /* * Returns the width of a string using XTextExtents. */ { XCharStruct bb; int dir, ascent, descent; XTextExtents(font, str, len, &dir, &ascent, &descent, &bb); return bb.width; } static void ti_cursor_on(win, ri) Window win; struct ti_info *ri; /* * Draws the cursor for the window. Uses pixel `pix'. */ { XFillRectangle(t_disp, win, set_gc(win, norm_pix, back_pix, norm_font->fid), ri->curxval + TI_HPAD + TI_CRSP, TI_VPAD, (ri->focus_flag ? 2 : 1), norm_font->ascent + norm_font->descent - 1); } static void ti_cursor_off(win, ri) Window win; struct ti_info *ri; /* * Draws the cursor for the window. Uses pixel `pix'. */ { XFillRectangle(t_disp, win, set_gc(win, back_pix, back_pix, norm_font->fid), ri->curxval + TI_HPAD + TI_CRSP, TI_VPAD, (ri->focus_flag ? 2 : 1), norm_font->ascent + norm_font->descent - 1); } static void ti_draw(win, ri, c_flag) Window win; struct ti_info *ri; int c_flag; /* * Draws the indicated text widget. This includes drawing the * text and cursor. If `c_flag' is set, the window will * be cleared first. */ { if (c_flag) XClearWindow(t_disp, win); /* Text */ XDrawImageString(t_disp, win, set_gc(win, norm_pix, back_pix, norm_font->fid), TI_HPAD, TI_VPAD+norm_font->ascent, ri->text, strlen(ri->text)); /* Cursor */ ti_cursor_on(win, ri); } static void ti_line(win, ri, pix) Window win; struct ti_info *ri; unsigned long pix; /* * Draws a status line beneath the text in a text widget to indicate * the user has moved into the text field. */ { XDrawLine(t_disp, win, set_gc(win, pix, back_pix, norm_font->fid), TI_HPAD, ri->line_y, TI_HPAD+ri->line_w, ri->line_y); } /* For debugging */ focus_evt(evt) XEvent *evt; { switch (evt->xfocus.mode) { case NotifyNormal: printf("NotifyNormal"); break; case NotifyGrab: printf("NotifyGrab"); break; case NotifyUngrab: printf("NotifyUngrab"); break; } printf(", detail = "); switch (evt->xfocus.detail) { case NotifyAncestor: printf("NotifyAncestor"); break; case NotifyVirtual: printf("NotifyVirtual"); break; case NotifyInferior: printf("NotifyInferior"); break; case NotifyNonlinear: printf("NotifyNonLinear"); break; case NotifyNonlinearVirtual: printf("NotifyNonLinearVirtual"); break; case NotifyPointer: printf("NotifyPointer"); break; case NotifyPointerRoot: printf("NotifyPointerRoot"); break; case NotifyDetailNone: printf("NotifyDetailNone"); break; } printf("\n"); } static xtb_hret ti_h(evt, info) XEvent *evt; xtb_data info; /* * Handles text input events. */ { Window win = evt->xany.window; struct ti_info *ri = (struct ti_info *) info; char keys[MAXKEYS], textcopy[MAXCHBUF]; xtb_hret rtn; int nbytes, i; switch (evt->type) { case Expose: ti_draw(win, ri, 0); rtn = XTB_HANDLED; break; case KeyPress: nbytes = XLookupString(&evt->xkey, keys, MAXKEYS, (KeySym *) 0, (XComposeStatus *) 0); for (i = 0; i < nbytes; i++) { (void) strcpy(textcopy, ri->text); if ((rtn = (*ri->func)(win, (int) keys[i], textcopy, ri->val)) == XTB_STOP) break; } break; case FocusIn: focus_evt(evt); if (evt->xfocus.detail != NotifyPointer) { ti_cursor_off(win, ri); ri->focus_flag = 1; ti_cursor_on(win, ri); } break; case FocusOut: focus_evt(evt); if (evt->xfocus.detail != NotifyPointer) { ti_cursor_off(win, ri); ri->focus_flag = 0; ti_cursor_on(win, ri); } break; case EnterNotify: ti_line(win, ri, norm_pix); rtn = XTB_HANDLED; break; case LeaveNotify: ti_line(win, ri, back_pix); rtn = XTB_HANDLED; break; case ButtonPress: /* Wait for release */ break; case ButtonRelease: /* Set input focus */ XSetInputFocus(t_disp, win, RevertToParent, CurrentTime); break; default: rtn = XTB_NOTDEF; break; } return rtn; } void xtb_ti_new(win, text, maxchar, func, val, frame) Window win; /* Parent window */ char *text; /* Initial text */ int maxchar; /* Maximum characters */ FNPTR( func, xtb_hret, (Window, int, char *, xtb_data *) ); /* Callback */ xtb_data val; /* User data */ xtb_frame *frame; /* Returned size */ /* * This routine creates a new editable text widget under `win' * with the initial text `text'. The widget contains only * one line of text which cannot exceed `maxchar' characters. * The size of the widget is returned in `frame'. Each * time a key is pressed in the window, `func' will be called * with the window, the character, a copy of the text, and `val'. * The state of the widget can be changed by the routines below. * May set window to zero if the maximum overall character width * (MAXCHBUF) is exceeded. */ { struct ti_info *info; if (maxchar >= MAXCHBUF) { frame->win = (Window) 0; return; } frame->width = XTextWidth(norm_font, "8", 1) * maxchar + 2*TI_HPAD; frame->height = norm_font->ascent + norm_font->descent + TI_VPAD + TI_LPAD; frame->x_loc = frame->y_loc = 0; frame->win = XCreateSimpleWindow(t_disp, win, 0, 0, frame->width, frame->height, TI_BRDR, norm_pix, back_pix); XSelectInput(t_disp, frame->win, ExposureMask|KeyPressMask| EnterWindowMask|LeaveWindowMask| FocusChangeMask|ButtonPressMask| ButtonReleaseMask); info = (struct ti_info *) malloc(sizeof(struct ti_info)); info->func = func; info->val = val; info->maxlen = maxchar; if (text) (void) strcpy(info->text, text); else info->text[0] = '\0'; info->curidx = strlen(info->text); info->curxval = text_width(norm_font, info->text, info->curidx); info->line_y = frame->height - 2; info->line_w = frame->width - 2 * TI_HPAD; info->focus_flag = 0; xtb_register(frame->win, ti_h, (xtb_data) info); XMapWindow(t_disp, frame->win); frame->width += (2 * TI_BRDR); frame->height += (2 * TI_BRDR); } void xtb_ti_get(win, text, val) Window win; /* Widget widnow */ char text[MAXCHBUF]; /* Filled in text */ xtb_data *val; /* User info */ /* * This routine returns the information associated with text * widget `win'. The text is filled into the passed buffer * `text' which should be MAXCHBUF characters in size. If * `val' is non-zero, the user supplied info is returned there. */ { struct ti_info *info = (struct ti_info *) xtb_lookup(win); if (val) *val = info->val; (void) strcpy(text, info->text); } int xtb_ti_set(win, text, val) Window win; /* Widget window */ char *text; /* Replacement text */ xtb_data val; /* User info */ /* * This routine sets the text of a text widget. The widget * will be redrawn. Note: for incremental changes, ti_ins and * ti_dch should be used. If `val' is non-zero, it will replace * the user information for the widget. The widget is redrawn. * Will return zero if `text' is too long. */ { struct ti_info *info = (struct ti_info *) xtb_lookup(win); int newlen; if (text) { if ((newlen = strlen(text)) >= info->maxlen) return 0; } else { newlen = 0; } info->curidx = newlen; if (text) (void) strcpy(info->text, text); else info->text[0] = '\0'; info->curxval = text_width(norm_font, info->text, info->curidx); if (val) info->val = val; ti_draw(win, info, 1); return 1; } int xtb_ti_ins(win, ch) Window win; /* Widget window */ int ch; /* Character */ /* * Inserts the character `ch' onto the end of the text for `win'. * Will return zero if there isn't any more room left. Does * all appropriate display updates. */ { struct ti_info *info = (struct ti_info *) xtb_lookup(win); char lstr[1]; if (info->curidx >= info->maxlen-1) return 0; info->text[info->curidx] = ch; info->text[info->curidx+1] = '\0'; /* Turn off cursor */ ti_cursor_off(win, info); /* Text */ lstr[0] = (char) ch; XDrawImageString(t_disp, win, set_gc(win, norm_pix, back_pix, norm_font->fid), info->curxval+TI_HPAD, TI_VPAD+norm_font->ascent, lstr, 1); info->curidx += 1; info->curxval += text_width(norm_font, lstr, 1); ti_cursor_on(win, info); return 1; } int xtb_ti_dch(win) Window win; /* Widget window */ /* * Deletes the character at the end of the text for `win'. Will * return zero if there aren't any characters to delete. Does * all appropriate display updates. */ { struct ti_info *info = (struct ti_info *) xtb_lookup(win); int chw; if (info->curidx == 0) return 0; /* Wipe out cursor */ ti_cursor_off(win, info); info->curidx -= 1; chw = text_width(norm_font, &(info->text[info->curidx]), 1); info->curxval -= chw; /* Wipe out character */ XClearArea(t_disp, win, info->curxval+TI_HPAD, TI_VPAD, (unsigned int) chw + 1, (unsigned int) norm_font->ascent + norm_font->descent, False); info->text[info->curidx] = '\0'; ti_cursor_on(win, info); return 1; } void xtb_ti_del(win, info) Window win; xtb_data *info; /* * Deletes an input text widget. User defined data is returned in `info'. */ { struct ti_info *ti; if (xtb_unregister(win, (xtb_data *) &ti)) { *info = ti->val; free((char *) ti); XDestroyWindow(t_disp, win); } } /* * Simple colored output frame - usually used for drawing lines */ void xtb_bk_new(win, width, height, frame) Window win; /* Parent window */ unsigned width, height; /* Size */ xtb_frame *frame; /* Returned size */ /* * This routine creates a new frame that displays a block * of color whose size is given by `width' and `height'. * It is usually used to draw lines. No user interaction * is defined for the frame. The color used is the default * foreground color set in xtb_init(). */ { frame->x_loc = frame->y_loc = 0; frame->width = width; frame->height = height; frame->win = XCreateSimpleWindow(t_disp, win, frame->x_loc, frame->y_loc, frame->width, frame->height, 0, norm_pix, norm_pix); XMapWindow(t_disp, frame->win); } void xtb_bk_del(win) Window win; /* * Deletes a block frame. */ { XDestroyWindow(t_disp, win); } /* * Formatting support */ #define ERROR(msg) printf("%s\n", msg); abort(); xtb_fmt *xtb_w(w) xtb_frame *w; /* * Returns formatting structure for a widget. */ { xtb_fmt *ret; ret = (xtb_fmt *) malloc((unsigned) sizeof(xtb_fmt)); ret->wid.type = W_TYPE; ret->wid.w = w; return ret; } VARARGS(xtb_hort, xtb_fmt *, (xtb_just just, int padding, int interspace, ...)) /* * Builds a horizontal structure */ { va_list ap; xtb_fmt *ret, *val; #ifdef __STDC__ va_start(ap, interspace); #else xtb_just just; int padding, interspace; va_start(ap); just = va_arg(ap, xtb_just); padding = va_arg(ap, int); interspace = va_arg(ap, int); #endif ret = (xtb_fmt *) malloc((unsigned) sizeof(xtb_fmt)); ret->align.type = A_TYPE; ret->align.dir = HORIZONTAL; ret->align.just = just; ret->align.padding = padding; ret->align.interspace = interspace; /* Build array of incoming xtb_fmt structures */ ret->align.ni = 0; while ((val = va_arg(ap, xtb_fmt *)) != (xtb_fmt *) 0) { if (ret->align.ni < MAX_BRANCH) { ret->align.items[ret->align.ni] = val; ret->align.ni++; } else { ERROR("too many branches\n"); } } return ret; } VARARGS(xtb_vert, xtb_fmt *, (xtb_just just, int padding, int interspace, ...)) /* * Builds a vertical structure */ { va_list ap; xtb_fmt *ret, *val; #ifdef __STDC__ va_start(ap, interspace); #else xtb_just just; int padding, interspace; va_start(ap); just = va_arg(ap, xtb_just); padding = va_arg(ap, int); interspace = va_arg(ap, int); #endif ret = (xtb_fmt *) malloc((unsigned) sizeof(xtb_fmt)); ret->align.type = A_TYPE; ret->align.dir = VERTICAL; ret->align.just = just; ret->align.padding = padding; ret->align.interspace = interspace; /* Build array of incoming xtb_fmt structures */ ret->align.ni = 0; while ((val = va_arg(ap, xtb_fmt *)) != (xtb_fmt *) 0) { if (ret->align.ni < MAX_BRANCH) { ret->align.items[ret->align.ni] = val; ret->align.ni++; } else { ERROR("too many branches\n"); } } return ret; } static void xtb_fmt_setpos(def, x, y) xtb_fmt *def; int x, y; /* * Sets all position fields of widgets in `def' to x,y. */ { int i; switch (def->type) { case W_TYPE: def->wid.w->x_loc = x; def->wid.w->y_loc = y; break; case A_TYPE: for (i = 0; i < def->align.ni; i++) { xtb_fmt_setpos(def->align.items[i], x, y); } break; default: ERROR("bad type"); } } static void xtb_fmt_addpos(def, x, y) xtb_fmt *def; int x, y; /* * Adds the offset specified to all position fields of widgets in `def'. */ { int i; switch (def->type) { case W_TYPE: def->wid.w->x_loc += x; def->wid.w->y_loc += y; break; case A_TYPE: for (i = 0; i < def->align.ni; i++) { xtb_fmt_addpos(def->align.items[i], x, y); } break; default: ERROR("bad type"); } } static void xtb_fmt_hort(nd, defs, widths, heights, just, pad, inter, rw, rh) int nd; /* Number of children */ xtb_fmt *defs[]; /* Definitions themselves */ int widths[]; /* Widths of children */ int heights[]; /* Heights of children */ xtb_just just; /* Justification */ int pad, inter; /* Padding and interspace */ int *rw, *rh; /* Returned size */ /* * Formats items horizontally subject to the widths and heights * of the items passed. */ { int i; int max_height = 0; int tot_width = 0; int xspot; /* Find parameters */ for (i = 0; i < nd; i++) { if (heights[i] > max_height) max_height = heights[i]; tot_width += widths[i]; } /* Place items -- assumes center justification */ xspot = pad; for (i = 0; i < nd; i++) { switch (just) { case XTB_TOP: xtb_fmt_addpos(defs[i], xspot, pad); break; case XTB_BOTTOM: xtb_fmt_addpos(defs[i], xspot, max_height - heights[i] + pad); break; case XTB_CENTER: default: /* Everyone else center */ xtb_fmt_addpos(defs[i], xspot, (max_height - heights[i])/2 + pad); break; } xspot += (widths[i] + inter); } /* Figure out resulting size */ *rw = tot_width + (nd-1)*inter + (2 * pad); *rh = max_height + (2 * pad); } static void xtb_fmt_vert(nd, defs, widths, heights, just, pad, inter, rw, rh) int nd; /* Number of children */ xtb_fmt *defs[]; /* Definitions themselves */ int widths[]; /* Widths of children */ int heights[]; /* Heights of children */ xtb_just just; /* Justification */ int pad, inter; /* Padding and interspace */ int *rw, *rh; /* Returned size */ /* * Formats items vertically subject to the widths and heights * of the items passed. */ { int i; int max_width = 0; int tot_height = 0; int yspot; /* Find parameters */ for (i = 0; i < nd; i++) { if (widths[i] > max_width) max_width = widths[i]; tot_height += heights[i]; } /* Place items -- assumes center justification */ yspot = pad; for (i = 0; i < nd; i++) { switch (just) { case XTB_LEFT: xtb_fmt_addpos(defs[i], pad, yspot); break; case XTB_RIGHT: xtb_fmt_addpos(defs[i], max_width - widths[i] + pad, yspot); break; case XTB_CENTER: default: /* Everyone else center */ xtb_fmt_addpos(defs[i], (max_width - widths[i])/2 + pad, yspot); break; } yspot += (heights[i] + inter); } /* Figure out resulting size */ *rw = max_width + (2 * pad); *rh = tot_height + (nd-1)*inter + (2 * pad); } static void xtb_fmt_top(def, w, h) xtb_fmt *def; unsigned *w, *h; /* * Recursive portion of formatter */ { unsigned widths[MAX_BRANCH]; unsigned heights[MAX_BRANCH]; int i; switch (def->type) { case A_TYPE: /* Formatting directive */ /* place children and determine sizes */ for (i = 0; i < def->align.ni; i++) { xtb_fmt_top(def->align.items[i], &(widths[i]), &(heights[i])); } /* now format based on direction */ switch (def->align.dir) { case HORIZONTAL: xtb_fmt_hort(def->align.ni, def->align.items, widths, heights, def->align.just, def->align.padding, def->align.interspace, w, h); break; case VERTICAL: xtb_fmt_vert(def->align.ni, def->align.items, widths, heights, def->align.just, def->align.padding, def->align.interspace, w, h); break; default: ERROR("bad direction"); } break; case W_TYPE: /* Simple widget - return size */ *w = def->wid.w->width; *h = def->wid.w->height; break; default: ERROR("bad type"); } } xtb_fmt *xtb_fmt_do(def, w, h) xtb_fmt *def; unsigned *w, *h; /* * Actually does formatting */ { /* First zero out all positions */ xtb_fmt_setpos(def, 0, 0); /* Now call recursive portion */ xtb_fmt_top(def, w, h); return def; } void xtb_fmt_free(def) xtb_fmt *def; /* * Frees resources associated with formatting routines */ { int i; if (def->type == A_TYPE) { for (i = 0; i < def->align.ni; i++) { xtb_fmt_free(def->align.items[i]); } } free((char *) def); } void xtb_mv_frames(nf, frames) int nf; /* Number of frames */ xtb_frame frames[]; /* Array of frames */ /* * Moves frames to the location indicated in the frame * structure for each item. */ { int i; for (i = 0; i < nf; i++) { XMoveWindow(t_disp, frames[i].win, frames[i].x_loc, frames[i].y_loc); } } \End\Of\Shar\ else echo "will not over write ./xgraph-11/xtb/xtb.c" fi echo "Finished archive 3 of 6"