/* ui.c: user interface toolkit * * 1999-10-11 Frank Suykens * * process_file_callback : If a NULL pointer is given for * open flags, no attempt is made to open a file * * * 1998-04-16 Philippe Bekaert * * CreateFormEntry(): NULL pointer accepted for Boolean *valid parameter * * 1998-04-10 Philippe Bekaert * * new functions CreateHelpSubMenu() and CreateScrolledWindow(). * * 1999-09-16 Philippe Bekaert * * handle_fet_type(): FET_STRING form entry type handling corrected. * (thanks to Frank Suykens) * */ #include "ui.h" #include "uit.h" #include "file.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; char *primitive_string, *p; int n; static char buf[MAX_LABEL_STRING_LENGTH+1]; XmStringInitContext (&context,cs); p = buf; n = 0; while (XmStringGetNextSegment (context,&primitive_string, &charset,&direction,&separator)) { int l; if (!primitive_string) { Warning("extract_normal_string", "no primitive string"); break; } l = strlen(primitive_string); if (n + 1 + l > MAX_LABEL_STRING_LENGTH) { Warning("extract_normal_string", "Buffer overflow. Recompile uit.c with a larger value for MAX_LABEL_STRING_LENGTH (currently %d)", MAX_LABEL_STRING_LENGTH); break; } if (p != buf) { *p++ = '\n'; n++; } /* separate segments with a '\n' */ strcpy(p, primitive_string); p += l; n += l; } 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; 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 TextFieldSetValue(Widget dialog, XtPointer client_data, XtPointer call_data) { TEXTFIELDCONTENTS *contents = (TEXTFIELDCONTENTS *)client_data; handle_fet_type(contents->type, contents->pvalue, contents->buf); XmTextFieldSetString(contents->textf, contents->buf); } static void TextFieldDestroy(Widget textf, XtPointer client_data, XtPointer call_data) { TEXTFIELDCONTENTS *contents = (TEXTFIELDCONTENTS *)client_data; if (contents->buflen >= 250) /* there;s one 250bytes buffer for all smaller fields */ Free((char *)contents->buf, contents->buflen+1); 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, value; char *buf; static char defbuf[250]; /* referenced to later in TextFieldSetValue etc... */ TEXTFIELDCONTENTS *contents; char *format = NULL; static Boolean bla; if (!valid) valid=&bla; 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); /* install a callback that will handle changes in the contents of the text field */ contents = (TEXTFIELDCONTENTS *)Alloc(sizeof(TEXTFIELDCONTENTS)); contents->type = type; contents->format = format; contents->pvalue = pvalue; contents->valid = valid; contents->buf = buf; contents->buflen = fieldlength; contents->textf = value; XtAddCallback(value, XmNvalueChangedCallback, TextFieldGetValue, (XtPointer)contents); XtAddCallback(value, XmNdestroyCallback, TextFieldDestroy, (XtPointer)contents); /* XtAddCallback(parent, XmNmapCallback, TextFieldSetValue, (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; static char defbuf[250]; /* referenced to later in TextFieldSetValue etc... */ TEXTFIELDCONTENTS *contents; char *format = NULL; static Boolean bla; if (!valid) valid=&bla; 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); /* install a callback that will handle changes in the contents of the text field */ contents = (TEXTFIELDCONTENTS *)Alloc(sizeof(TEXTFIELDCONTENTS)); contents->type = type; contents->format = format; contents->pvalue = pvalue; contents->valid = valid; contents->buf = buf; contents->buflen = fieldlength; contents->textf = value; XtAddCallback(value, XmNvalueChangedCallback, TextFieldGetValue, (XtPointer)contents); XtAddCallback(value, XmNdestroyCallback, TextFieldDestroy, (XtPointer)contents); XtAddCallback(dialog, XmNmapCallback, TextFieldSetValue, (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 *open_mode = fsdata->open_mode; int ispipe = FALSE, succes; FILE *fp = (FILE *)NULL; /* check the open mode */ if(!open_mode) { /* No open mode, just call the callback with the filename, no open file */ /* call the user supplied procedure to process the file */ succes = fsdata->process_file(filename, fp, ispipe, dialog); } else { fp = OpenFile(filename, open_mode, &ispipe); /* call the user supplied procedure to process the file */ succes = fsdata->process_file(filename, fp, ispipe, dialog); CloseFile(fp, ispipe); } /* 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; } static void browse_filename_okcallback(Widget dialog, XtPointer client_data, XtPointer call_data) { Widget formEntry = (Widget)client_data; char *filename = extract_normal_string (((XmSelectionBoxCallbackStruct *)call_data)->value); XmTextFieldSetString(formEntry, filename); XtUnmanageChild(dialog); } /* CreatFileAndBrowseEntry : creates a formentry with a button next to it. The formentry holds a file name that can be chosen using the browse button. The browse button spawns a file selection dialog. !!! labelname currently unused, routine based on text field return value of 'CreateFormEntry' !!!! */ Widget CreateFileAndBrowseEntry(Widget parent, char *labelname, char *textfname, XtPointer pvalue, Boolean *valid, int fieldlength) { Widget rowcol=(Widget)NULL; Widget formEntry, button, dialog; rowcol = CreateRowColumn(parent, "fileAndBrowseRowCol"); formEntry = CreateFormEntry(rowcol, NULL, textfname, FET_STRING, pvalue, valid, fieldlength); button = XtVaCreateManagedWidget("fileAndBrowseButton", xmPushButtonWidgetClass, rowcol, NULL); dialog = XmCreateFileSelectionDialog(button, "fileAndBrowseDialog", visargs, nrvisargs); XtVaSetValues(dialog, XmNautoUnmanage, False, NULL); XtAddCallback(dialog, XmNcancelCallback, unmanage_callback, NULL); XtAddCallback(dialog, XmNokCallback, browse_filename_okcallback, (XtPointer)formEntry); UnmanageSelectionBoxChild(dialog, XmDIALOG_HELP_BUTTON); XtAddCallback(button, XmNactivateCallback, DoPopup, (XtPointer)dialog); XtManageChild(rowcol); return rowcol; }