/* ui.c: user interface toolkit * * 1998-04-10 Philippe Bekaert * * new functions CreateHelSubMenu() and CreateScrolledWindow(). * */ #include "ui.h" #include "uit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "error.h" #include "pools.h" /* Enables state changes of the input widget */ void EnableWidget(Widget widget) { XtSetSensitive(widget, True); } /* Disables state changes of the input widget */ void DisableWidget(Widget widget) { XtSetSensitive(widget, False); } /* Creates a push button with given widget name, parent widget, activate callback * (no activate callback if NULL is passed), and client data for the activate * callback procedure. */ Widget CreatePushButton(Widget parent, char *widgetname, void (*activate_callback)(Widget, XtPointer, XtPointer), XtPointer client_data) { Widget pushb; pushb = XtVaCreateManagedWidget(widgetname, xmPushButtonWidgetClass, parent, NULL); if (activate_callback) XtAddCallback(pushb, XmNactivateCallback, activate_callback, client_data); return pushb; } /* creates a template dialog */ Widget CreateDialog(Widget parent, char *name) { return XmCreateTemplateDialog(parent, name, visargs, nrvisargs); } void SetDialogTitle(Widget dialog, char *title) { XtVaSetValues(dialog, XtVaTypedArg, XmNtitle, XmRString, title, strlen(title)+1, NULL); } /* unmanages a message box child (e.g. for a template dialog created with * CreateDialog(). */ void UnmanageMessageBoxChild(Widget dialog, unsigned char child) { Widget childw = XmMessageBoxGetChild(dialog, child); XtUnmanageChild(childw); } /* manages a message box child */ void ManageMessageBoxChild(Widget dialog, unsigned char child) { Widget childw = XmMessageBoxGetChild(dialog, child); XtManageChild(childw); } /* creates a radio box */ Widget CreateRadioBox(Widget parent, char *name) { return XmCreateRadioBox(parent, name, visargs, nrvisargs); } /* creates a rowcolumn widget */ Widget CreateRowColumn(Widget parent, char *name) { return XmCreateRowColumn(parent, name, visargs, nrvisargs); } /* Creates and returns a label widget with given name */ Widget CreateLabel(Widget parent, char *name) { return XtVaCreateManagedWidget(name, xmLabelWidgetClass, parent, NULL); } /* stolen from the Motif demos */ /* support routine to get normal string from an XmString (Motif compound string) */ char *extract_normal_string(XmString cs) { XmStringContext context; XmStringCharSet charset; XmStringDirection direction; Boolean separator; static char *primitive_string; static char buf[MAX_LABEL_STRING_LENGTH+1], *p; XmStringInitContext (&context,cs); p = buf; while (XmStringGetNextSegment (context,&primitive_string, &charset,&direction,&separator)) { if (p != buf) *p++ = '\n'; /* separate segments with a '\n' */ if (!primitive_string) { Warning("extract_normal_string", "no primitive string"); break; } strcpy(p, primitive_string); p += strlen(primitive_string); } XmStringFreeContext (context); return buf; } /* Returns the message string displayed on the label widget. * The string should be no longer than MAX_LABEL_STRING_LENGTH * characters! */ char *GetLabelString(Widget label) { XmString xmstr; XtVaGetValues(label, XmNlabelString, &xmstr, NULL); return strdup(extract_normal_string(xmstr)); } /* Sets the message displayed on a label widget */ void SetLabelString(Widget label, char *message) { XtVaSetValues(label, XtVaTypedArg, XmNlabelString, XmRString, message, strlen(message)+1, NULL); } /* Creates and returns a form widget with given name */ Widget CreateForm(Widget parent, char *name) { return XtVaCreateWidget(name, xmFormWidgetClass, parent, NULL); } /* Creates and returns a frame widget with name specified by framename. * If frametitlename is not NULL, a label widget is created with that name, * which is a child of the frame with type XmFRAME_TITLE_CHILD. */ Widget CreateFrame(Widget parent, char *framename, char *frametitlename) { Widget frame, title; frame = XtVaCreateManagedWidget(framename, xmFrameWidgetClass, parent, NULL); if (frametitlename) { title = XtVaCreateManagedWidget(frametitlename, xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, NULL); } return frame; } /* default valuechanged callback for toggle buttons. */ static void default_toggle_callback(Widget w, XtPointer client_data, XtPointer call_data) { int *state = (int *)client_data; int set = (((XmToggleButtonCallbackStruct *)call_data)->set == XmSET); *state = set; } /* Creates and returns a toggle button with given name and parent widget. The initial * state will be "SET" if initially_set is TRUE or "UNSET" if FALSE. If * 'toggle_callback' is not null, it will be called with the given client_data * each time the toggle button changes state. If 'toggle_callback' is * null, but 'client_data' is not null, a default toggle callback is * installed that interprets 'client_data' as a pointer to an int and * will fill in 1 or 0 according to the state of the toggle button. */ Widget CreateToggleButton(Widget parent, char *name, Boolean initially_set, void (*toggle_callback)(Widget, XtPointer, XtPointer), XtPointer client_data) { Widget toggleB; toggleB = XtVaCreateManagedWidget(name, xmToggleButtonWidgetClass, parent, XmNset, initially_set, NULL); if (toggle_callback) XtAddCallback(toggleB, XmNvalueChangedCallback, toggle_callback, client_data); else if (client_data) XtAddCallback(toggleB, XmNvalueChangedCallback, default_toggle_callback, client_data); return toggleB; } /* Creates and returns a new toplevel shell widget with given * window title. Use XtRealizeWidget(the_shell_widget) to bring * the separate window to the screen and XtDestroyWidget(the_shell_widget) * to remove it again. */ Widget CreateShell(char *title) { return XtAppCreateShell(title, APP_CLASS_NAME, topLevelShellWidgetClass, display, visargs, nrvisargs); } /* Creates and returns a menu bar with given name and parent widget */ Widget CreateMenuBar(Widget parent, char *menuname) { return XmCreateMenuBar(parent, menuname, visargs, nrvisargs); } /* Creates a popup menu (no button involved), position with XmMenuPosition() * and pop up with XtManageChild(). */ Widget CreatePopupMenu(Widget parent, char *menuname) { return XmCreatePopupMenu(parent, menuname, visargs, nrvisargs); } /* Creates a cascade button and corresponding pulldown menu with given * parent and names. */ Widget CreateSubMenu(Widget parent, char *buttonname, char *menuname) { Widget menu, button; button = XtVaCreateManagedWidget(buttonname, xmCascadeButtonWidgetClass, parent, NULL); menu = XmCreatePulldownMenu(parent, menuname, visargs, nrvisargs); XtVaSetValues(button, XmNsubMenuId, menu, NULL); return menu; } /* Creates a cascade button and corresponding help pulldown menu with given * parent and names. (sets also the XmNmenuHelpWidget resource) */ Widget CreateHelpSubMenu(Widget parent, char *buttonname, char *menuname) { Widget menu, button; button = XtVaCreateManagedWidget(buttonname, xmCascadeButtonWidgetClass, parent, NULL); menu = XmCreatePulldownMenu(parent, menuname, visargs, nrvisargs); XtVaSetValues(button, XmNsubMenuId, menu, NULL); XtVaSetValues(parent, XmNmenuHelpWidget, button, NULL); return menu; } /* Creates an option menu and corresponding submenu with given parent and * names. The OptionMenu widget (the button) is returned. Use * CreateOptionsButton() to create buttons in the menu. */ Widget CreateOptionMenu(Widget parent, char *buttonname, char *submenuname) { Widget menu, button; Arg args[8]; int n = 0; menu = XmCreatePulldownMenu(parent, submenuname, visargs, nrvisargs); for (n=0; nvalid) = (sscanf(text, contents->format, contents->pvalue)==1); free(text); } static void TextFieldDestroy(Widget textf, XtPointer client_data, XtPointer call_data) { TEXTFIELDCONTENTS *contents = (TEXTFIELDCONTENTS *)client_data; Free((char *)contents, sizeof(TEXTFIELDCONTENTS)); } /* Creates a form entry: a label and text field widget pair that can be used * to construct forms. The label widget, indicating the meaning of the value that * can be edited in the text field widget, is optional. If no such label * widget is wanted, 'labelname' should be a NULL pointer. 'textfname' is the name * of the text field widget. 'type' determines the type of the value in the text field. * 'pvalue' is a pointer to the value to be displayed in the text field. * The value is updated each time after text is deleted or inserted from/into the text * field. 'valid' will contain True if the text field has valid contents * and False if not. The text field contents are considered to be valid if * sscanf(textfieldcontents, format, pvalue) returns 1. 'fieldlength' determines the * width (in characters) of the text field. The field length should be large enough to * contain the initial contents of the field. 'fieldlength' can be zero, in which case * the default is used (250 characters buffer for holding the initial contents * of the field and 20 characters width text field widget). If 'labelname' is not NULL, * the label and text field widget are packed together in a form with * name 'formEntry'. The widget returned is the text field widget is 'labelname' * is NULL, or the form widget containing both the label and text field widget * is 'labelname' is not NULL. */ Widget CreateFormEntry(Widget parent, char *labelname, char *textfname, FORMENTRYTYPE type, XtPointer pvalue, Boolean *valid, int fieldlength) { Widget entry=(Widget)NULL, label, value; char *buf, defbuf[250]; TEXTFIELDCONTENTS *contents; char *format = NULL; if (fieldlength >= 250) buf = (char *)Alloc(fieldlength+1); else buf = defbuf; if (labelname) { /* create a form widget to hold the label and text field widget */ entry = XtVaCreateWidget("formEntry", xmFormWidgetClass, parent, NULL); } /* create a text field widget */ value = XtVaCreateManagedWidget(textfname, xmTextFieldWidgetClass, labelname ? entry : parent, XmNrightAttachment, XmATTACH_FORM, NULL); if (fieldlength>0) XtVaSetValues(value, XmNmaxLength, fieldlength, NULL); format = handle_fet_type(type, pvalue, buf); *valid = True; XmTextFieldSetString(value, buf); if (fieldlength >= 250) Free((char *)buf, fieldlength+1); /* install a callback that will handle changes in the contents of the text field */ contents = (TEXTFIELDCONTENTS *)Alloc(sizeof(TEXTFIELDCONTENTS)); contents->format = format; contents->pvalue = pvalue; contents->valid = valid; XtAddCallback(value, XmNvalueChangedCallback, TextFieldGetValue, (XtPointer)contents); XtAddCallback(value, XmNdestroyCallback, TextFieldDestroy, (XtPointer)contents); if (labelname) { /* create a label widget which is positioned left of the text field widget */ label = XtVaCreateManagedWidget(labelname, xmLabelWidgetClass, entry, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, value, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); XtManageChild(entry); return entry; } else return value; } /* Creates a prompt dialog with given parent and name, asking for a * value of specified type to be filled in in pvalue. valid will contain * TRUE if the value that was fille din is valid and FALSE if invalid. * If fieldlength is not zero, it defines the length of the editable text * field in the prompt dialog. */ Widget CreatePromptDialog(Widget parent, char *name, FORMENTRYTYPE type, XtPointer pvalue, Boolean *valid, int fieldlength) { Widget dialog, value; char *buf, defbuf[250]; TEXTFIELDCONTENTS *contents; char *format = NULL; if (fieldlength >= 250) buf = (char *)Alloc(fieldlength+1); else buf = defbuf; dialog = XmCreatePromptDialog(parent, name, visargs, nrvisargs); value = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT); if (fieldlength>0) XtVaSetValues(value, XmNmaxLength, fieldlength, NULL); format = handle_fet_type(type, pvalue, buf); *valid = True; XmTextFieldSetString(value, buf); if (fieldlength >= 250) Free((char *)buf, fieldlength+1); /* install a callback that will handle changes in the contents of the text field */ contents = (TEXTFIELDCONTENTS *)Alloc(sizeof(TEXTFIELDCONTENTS)); contents->format = format; contents->pvalue = pvalue; contents->valid = valid; XtAddCallback(value, XmNvalueChangedCallback, TextFieldGetValue, (XtPointer)contents); XtAddCallback(value, XmNdestroyCallback, TextFieldDestroy, (XtPointer)contents); UnmanageSelectionBoxChild(dialog, XmDIALOG_HELP_BUTTON); return dialog; } /* unmanages a selection box child (e.g. for a prompt dialog created with * CreatePromptDialog() or a file selection dialog. */ void UnmanageSelectionBoxChild(Widget dialog, unsigned char child) { Widget childw = XmSelectionBoxGetChild(dialog, child); XtUnmanageChild(childw); } /* manages a selection box child */ void ManageSelectionBoxChild(Widget dialog, unsigned char child) { Widget childw = XmSelectionBoxGetChild(dialog, child); XtManageChild(childw); } static void unmanage_callback(Widget dialog, XtPointer client_data, XtPointer call_data) { XtUnmanageChild(dialog); } typedef struct FSDATA { char *open_mode; int (*process_file)(char *fname, FILE *fp, int ispipe, Widget fsbox); } FSDATA; static void process_file_callback(Widget dialog, XtPointer client_data, XtPointer call_data) { FSDATA *fsdata = (FSDATA *)client_data; char *filename = extract_normal_string (((XmSelectionBoxCallbackStruct *)call_data)->value); char *ext, *cmd, *open_mode = fsdata->open_mode; int ispipe = FALSE, succes; FILE *fp = (FILE *)NULL; /* check the open mode */ if (!open_mode || (*open_mode != 'r' && *open_mode != 'w' && *open_mode != 'a')) { Fatal(2, NULL, "Invalid fopen() mode '%s'\n", open_mode ? open_mode : "(null)"); return; } if (filename[0] != '\0' && filename[strlen(filename)-1] != '/') { /* open the file */ cmd = Alloc(strlen(filename) + 20); ext = strrchr(filename, '.'); if (filename[0] == '|') { sprintf(cmd, "%s", filename+1); fp = popen(cmd, open_mode); ispipe = TRUE; } else if (ext && strcmp(ext, ".gz")==0) { if (*open_mode == 'r') sprintf(cmd, "gunzip < %s", filename); else sprintf(cmd, "gzip > %s", filename); fp = popen(cmd, open_mode); ispipe = TRUE; } else if (ext && strcmp(ext, ".Z")==0) { if (*open_mode == 'r') sprintf(cmd, "uncompress < %s", filename); else sprintf(cmd, "compress > %s", filename); fp = popen(cmd, open_mode); ispipe = TRUE; } else { fp = fopen(filename, open_mode); ispipe = FALSE; } Free(cmd, strlen(filename) + 20); if (!fp) { Error(NULL, "Can't open file '%s' for %s", filename, *open_mode == 'r' ? "reading" : "writing"); return; } } /* call the user supplied procedure to process the file */ succes = fsdata->process_file(filename, fp, ispipe, dialog); if (fp) { /* close the file */ if (ispipe) pclose(fp); else fclose(fp); } /* unmanage the file selection dialog if processing was succesful */ if (succes) XtUnmanageChild(dialog); } /* Creates and returns a file selection dialog with given parent and * name. If a 'process_file' function is specified, an okCallback * function is installed that will try to open the file with specified * 'open_mode', call the 'process_file' function passing on * the file name, the FILE pointer (possibly NULL if no filename is * entered), a flag indicating whether the file is a pipe or a regular * file and the file selection box Widget. Finally the opened file is * closed and the file selection box unmanaged if the 'process_file' * function returned nonzero. The file name suffices .gz and .Z * are understood, and when the file name starts with a '|', it is * interpreted as a command to open a pipe to/from. */ Widget CreateFileSelectionDialog(Widget parent, char *name, int (*process_file)(char *fname, FILE *fp, int ispipe, Widget fsbox), char *open_mode) { Widget dialog = XmCreateFileSelectionDialog(parent, name, visargs, nrvisargs); XtVaSetValues(dialog, XmNautoUnmanage, False, NULL); XtAddCallback(dialog, XmNcancelCallback, unmanage_callback, NULL); if (process_file) { FSDATA *fsdata = (FSDATA *)Alloc(sizeof(FSDATA)); fsdata->open_mode = open_mode; fsdata->process_file = process_file; XtAddCallback(dialog, XmNokCallback, process_file_callback, (XtPointer)fsdata); } UnmanageSelectionBoxChild(dialog, XmDIALOG_HELP_BUTTON); return dialog; } /* Creates and returns a separator widget with given name */ Widget CreateSeparator(Widget parent, char *name) { return XtVaCreateManagedWidget(name, xmSeparatorWidgetClass, parent, NULL); } /* Creates a scrolled window widget with given parent widget and name. * If 'create_child' is NULL, a XmLabel widget with name 'childname' is created * as the work window child. Otherwise, 'create_child' is called * in order to create a more complex child. */ Widget CreateScrolledWindow(Widget parent, char *name, Widget (*create_child)(Widget parent, char *childname), char *child_name) { Widget scrolledW, child; scrolledW = XtVaCreateManagedWidget(name, xmScrolledWindowWidgetClass, parent, NULL); if (create_child) child = create_child(scrolledW, child_name); else child = CreateLabel(scrolledW, child_name); XtVaSetValues(scrolledW, XmNworkWindow, child, NULL); return scrolledW; }