/* * Motif Tools Library, Version 3.1 * $Id: AskForString.c,v 1.1.1.1 2001/07/18 11:06:01 root Exp $ * * Written by David Flanagan. * Copyright (c) 1992-2001 by David Flanagan. * All Rights Reserved. See the file COPYRIGHT for details. * This is open source software. See the file LICENSE for details. * There is no warranty for this software. See NO_WARRANTY for details. * * $Log: AskForString.c,v $ * Revision 1.1.1.1 2001/07/18 11:06:01 root * Initial checkin. * * Revision 1.1 2001/06/12 15:00:21 andre * AA-2001-06-12-0: replaced Xmt212 by Xmt310 * (http://sourceforge.net/projects/motiftools) with * our xmt212 patches applied * * */ #include #include #include #include #include #include #include #if NeedFunctionPrototypes static void CreateStringDialog(XmtPerScreenInfo *info) #else static void CreateStringDialog(info) XmtPerScreenInfo *info; #endif { Widget dshell; Widget dialog; Widget cancel, help; Arg args[5]; int i; /* create the dialog shell */ i = 0; XtSetArg(args[i], XmNallowShellResize, True); i++; dshell = XmCreateDialogShell(info->topmost_shell, XmtSTRING_DIALOG_SHELL_NAME, args, i); /* create the dialog box itself */ i = 0; XtSetArg(args[i], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); i++; XtSetArg(args[i], XmNdialogType, XmDIALOG_PROMPT); i++; XtSetArg(args[i], XmNautoUnmanage, False); i++; XtSetArg(args[i], XmNdefaultPosition, False); i++; dialog = XmCreateSelectionBox(dshell, XmtSTRING_DIALOG_NAME, args, i); /* add callbacks on all the dialog buttons */ cancel = XmSelectionBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON); help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON); XtAddCallback(cancel, XmNactivateCallback, _XmtCancelCallback, (XtPointer)info); XtAddCallback(help, XmNactivateCallback, _XmtHelpCallback, (XtPointer)info); /* add a callback for f.close */ XmtAddDeleteCallback(dshell, XmDO_NOTHING, _XmtCancelCallback, (XtPointer)info); /* cache the dialog in the DialogInfo structure */ info->string_dialog = dialog; } /* error messages localized in DoStringDialog, used in callback procs below */ static String bad_int_message, bad_double_message; static String too_small_message, too_big_message; typedef struct { XmtPerScreenInfo *info; int int_min, int_max, int_value; double double_min, double_max, double_value; } VerifyCallbackStruct; /* * This callback procedure gets registered on the Ok button and * checks that the user's input is a legal integer, and if the * integer bounds are not equal to one another, it also checks * that the input integer is between those bounds. If any of * these tests fail, it display an error with XmtDisplayError. * If all pass, it stores the converted integer into the * VerifyCallbackStruct for later use by the calling routine, * and sets info->state so that the recursive loop terminates */ /* ARGSUSED */ #if NeedFunctionPrototypes static void IntVerifyCallback(Widget w, XtPointer tag, XtPointer call_data) #else static void IntVerifyCallback(w, tag, call_data) Widget w; XtPointer tag; XtPointer call_data; #endif { VerifyCallbackStruct *data = (VerifyCallbackStruct *) tag; Widget text_w; String text_value; int int_value; Boolean check_bounds; text_w = XmSelectionBoxGetChild(data->info->string_dialog, XmDIALOG_TEXT); text_value = XmTextGetString(text_w); check_bounds = (data->int_min < data->int_max); if (sscanf(text_value, "%d", &int_value) != 1) /* bad input */ XmtDisplayError(data->info->string_dialog, XmtBAD_INT_DIALOG, bad_int_message); else if (check_bounds &&(int_value < data->int_min)) XmtDisplayError(data->info->string_dialog, XmtTOO_SMALL_DIALOG, too_small_message); else if (check_bounds && (int_value > data->int_max)) XmtDisplayError(data->info->string_dialog, XmtTOO_BIG_DIALOG, too_big_message); else { /* if input is good, store it and exit event loop */ data->info->blocked = False; data->info->button = XmtOkButton; data->int_value = int_value; } XtFree(text_value); } /* * This callback is like IntVerifyCallback above, but uses doubles */ /* ARGSUSED */ #if NeedFunctionPrototypes static void DoubleVerifyCallback(Widget w, XtPointer tag, XtPointer call_data) #else static void DoubleVerifyCallback(w, tag, call_data) Widget w; XtPointer tag; XtPointer call_data; #endif { VerifyCallbackStruct *data = (VerifyCallbackStruct *) tag; Widget text_w; String text_value; double double_value; Boolean check_bounds; text_w = XmSelectionBoxGetChild(data->info->string_dialog, XmDIALOG_TEXT); text_value = XmTextGetString(text_w); check_bounds = (data->double_min < data->double_max); if (sscanf(text_value, "%lg", &double_value) != 1) /* bad input */ XmtDisplayError(data->info->string_dialog, XmtBAD_DOUBLE_DIALOG, bad_double_message); else if (check_bounds &&(double_value < data->double_min)) XmtDisplayError(data->info->string_dialog, XmtTOO_SMALL_DIALOG, too_small_message); else if (check_bounds && (double_value > data->double_max)) XmtDisplayError(data->info->string_dialog, XmtTOO_BIG_DIALOG, too_big_message); else { /* if input is good, store it and exit event loop */ data->info->blocked = False; data->info->button = XmtOkButton; data->double_value = double_value; } XtFree(text_value); } typedef struct { String message; String title; String help_text; } StringDialogData; static XtResource string_resources[] = { {XmtNmessage, XmtCMessage, XtRString, sizeof(String), XtOffsetOf(StringDialogData, message), XtRString, NULL}, {XmtNtitle, XmtCTitle, XtRString, sizeof(String), XtOffsetOf(StringDialogData, title), XtRString, NULL}, {XmtNhelpText, XmtCHelpText, XtRString, sizeof(String), XtOffsetOf(StringDialogData, help_text), XtRString, NULL} }; /* possible values for the type argument of DoStringDialog */ #define XmtSTRING 1 #define XmtINT 2 #define XmtDOUBLE 3 #if NeedFunctionPrototypes static Boolean DoStringDialog(Widget w, StringConst dialog_name, StringConst default_prompt, String buffer, int buffer_length, int *int_return, double *double_return, int int_min, int int_max, double double_min, double double_max, StringConst default_help, int type) #else static Boolean DoStringDialog(w, dialog_name, default_prompt, buffer, buffer_length, int_return, double_return, int_min, int_max, double_min, double_max, default_help, type) Widget w; StringConst dialog_name; StringConst default_prompt; String buffer; int buffer_length; int *int_return; double *double_return; int int_min; int int_max; double double_min; double double_max; StringConst default_help; int type; #endif { Widget shell = XmtGetShell(w); Widget text_w, okay_w, help_w; XmtPerScreenInfo *info = XmtGetPerScreenInfo(shell); StringDialogData data; String dialog_class; String default_title; String default_text; char local_buffer[50]; XtCallbackProc ok_callback; XtPointer ok_client_data; VerifyCallbackStruct client_data_struct; String value; XmString message, title; Arg args[10]; int i; static String default_string_title; static String default_int_title; static String default_double_title; /* make sure the shell we pop up over is not a menu shell! */ while(XtIsOverrideShell(shell)) shell = XmtGetShell(XtParent(shell)); /* localize strings, first time through */ if (!default_string_title) { default_string_title = XmtLocalize2(w, XmtSTRING_DIALOG_TITLE_DEFAULT, "XmtAskForString", "title"); default_int_title = XmtLocalize2(w, XmtINT_DIALOG_TITLE_DEFAULT, "XmtAskForInteger", "title"); default_double_title = XmtLocalize2(w, XmtDOUBLE_DIALOG_TITLE_DEFAULT, "XmtAskForDouble", "title"); bad_int_message = XmtLocalize2(w, XmtBAD_INT_MESSAGE, "XmtAskForInteger", "badInput"); bad_double_message = XmtLocalize2(w, XmtBAD_DOUBLE_MESSAGE, "XmtAskForDouble", "badInput"); too_small_message = XmtLocalize2(w, XmtTOO_SMALL_MESSAGE, "XmtAskForInteger", "tooSmall"); too_big_message = XmtLocalize2(w, XmtTOO_BIG_MESSAGE, "XmtAskForInteger", "tooBig"); } /* if there's no cached dialog, create one. */ if (info->string_dialog == NULL) CreateStringDialog(info); /* get handles to the text widget and help button within the dialog */ text_w = XmSelectionBoxGetChild(info->string_dialog, XmDIALOG_TEXT); okay_w = XmSelectionBoxGetChild(info->string_dialog, XmDIALOG_OK_BUTTON); help_w = XmSelectionBoxGetChild(info->string_dialog, XmDIALOG_HELP_BUTTON); if (default_prompt == NULL) default_prompt = ""; if (default_help == NULL) default_help= ""; /* resource lists differ by type of the dialog */ switch(type) { case XmtSTRING: default: default_title = default_string_title; dialog_class = XmtCStringDialog; break; case XmtINT: default_title = default_int_title; dialog_class = XmtCIntDialog; break; case XmtDOUBLE: default_title = default_double_title; dialog_class = XmtCDoubleDialog; break; } /* if this dialog has a name, look up its resources */ if (dialog_name != NULL) { string_resources[0].default_addr = (XtPointer) default_prompt; string_resources[1].default_addr = (XtPointer) default_title; string_resources[2].default_addr = (XtPointer) default_help; XtGetSubresources(shell, (XtPointer)&data, (String)dialog_name, dialog_class, string_resources, XtNumber(string_resources), NULL, 0); } else { /* otherwise use arguments as defaults */ data.message = (String) default_prompt; data.title = default_title; data.help_text = (String) default_help; } /* figure out default text for the text widget */ switch(type) { case XmtSTRING: default: default_text = buffer; break; case XmtINT: sprintf(local_buffer, "%d", *int_return); default_text = local_buffer; buffer_length = 50; break; case XmtDOUBLE: sprintf(local_buffer, "%g", *double_return); default_text = local_buffer; buffer_length = 50; break; } /* set resources on the dialog box and the text widget within it. */ message = XmtCreateLocalizedXmString(w, data.message); title = XmtCreateLocalizedXmString(w, data.title); i = 0; XtSetArg(args[i], XmNselectionLabelString, message); i++; XtSetArg(args[i], XmNdialogTitle, title); i++; XtSetValues(info->string_dialog, args, i); XmStringFree(message); XmStringFree(title); i = 0; XtSetArg(args[i], XmNvalue, default_text); i++; XtSetArg(args[i], XmNmaxLength, buffer_length -1); i++; XtSetValues(text_w, args, i); /* if there is help text, make the button sensitive, * and put help text where the callback procedure can find it. */ if ((data.help_text != NULL) && (data.help_text[0] != '\0')) { XtSetSensitive(help_w, True); info->help_text = data.help_text; } else { XtSetSensitive(help_w, False); info->help_text = NULL; } /* set the appropriate callback on the Ok button */ switch(type) { case XmtSTRING: default: ok_callback = _XmtOkCallback; ok_client_data = (XtPointer) info; break; case XmtINT: client_data_struct.info = info; client_data_struct.int_min = int_min; client_data_struct.int_max = int_max; ok_callback = IntVerifyCallback; ok_client_data = (XtPointer) &client_data_struct; break; case XmtDOUBLE: client_data_struct.info = info; client_data_struct.double_min = double_min; client_data_struct.double_max = double_max; ok_callback = DoubleVerifyCallback; ok_client_data = (XtPointer) &client_data_struct; break; } XtAddCallback(okay_w, XmNactivateCallback, ok_callback, ok_client_data); /* Tell the dialog who it is transient for */ XtVaSetValues(XtParent(info->string_dialog), XtNtransientFor, shell, NULL); /* position the dialog, set initial focus, and pop it up */ XmtDialogPosition(info->string_dialog, shell); XmtSetInitialFocus(info->string_dialog, text_w); XmTextSetInsertionPosition(text_w, XmTextGetLastPosition(text_w)); XtManageChild(info->string_dialog); /* * Enter a recursive event loop. * The callback registered on the okay and cancel buttons when * this dialog was created will cause info->button to change * when one of those buttons is pressed. */ info->blocked = True; XmtBlock(info->string_dialog, &info->blocked); /* pop down the dialog */ XtUnmanageChild(info->string_dialog); /* make sure what is underneath gets cleaned up * (the calling routine might act on the user's returned * input and not handle events for awhile.) */ XSync(XtDisplay(info->string_dialog), 0); XmUpdateDisplay(info->string_dialog); /* unregister the okay callback we set on the dialog */ XtRemoveCallback(okay_w, XmNactivateCallback, ok_callback, ok_client_data); /* if user clicked Cancel, return False */ if (info->button == XmtCancelButton) return False; /* * otherwise, put the user's input into the buffer or * set the int or double return value, as appropriate * and return True */ if (type == XmtSTRING) { value = XmTextGetString(text_w); strncpy(buffer, value, buffer_length); buffer[buffer_length-1] = '\0'; /* just in case */ XtFree(value); } else if (type == XmtINT) *int_return = client_data_struct.int_value; else if (type == XmtDOUBLE) *double_return = client_data_struct.double_value; return True; } #if NeedFunctionPrototypes Boolean XmtAskForString(Widget w, StringConst dialog_name, StringConst default_prompt, String buffer,int buffer_length, StringConst default_help) #else Boolean XmtAskForString(w, dialog_name, default_prompt, buffer, buffer_length, default_help) Widget w; StringConst dialog_name; StringConst default_prompt; String buffer; int buffer_length; StringConst default_help; #endif { return DoStringDialog(w, dialog_name, default_prompt, buffer, buffer_length, NULL, NULL, 0,0, 0.0, 0.0, default_help, XmtSTRING); } #if NeedFunctionPrototypes Boolean XmtAskForInteger(Widget w, StringConst dialog_name, StringConst default_prompt, int *value, int min, int max, StringConst default_help) #else Boolean XmtAskForInteger(w, dialog_name, default_prompt, value, min, max, default_help) Widget w; StringConst dialog_name; StringConst default_prompt; int *value; int min; int max; StringConst default_help; #endif { return DoStringDialog(w, dialog_name, default_prompt, NULL, 0, value, NULL, min, max, 0.0, 0.0, default_help, XmtINT); } #if NeedFunctionPrototypes Boolean XmtAskForDouble(Widget w, StringConst dialog_name, StringConst default_prompt, double *value, double min, double max, StringConst default_help) #else Boolean XmtAskForDouble(w, dialog_name, default_prompt, value, min, max, default_help) Widget w; StringConst dialog_name; StringConst default_prompt; double *value; double min; double max; StringConst default_help; #endif { return DoStringDialog(w, dialog_name, default_prompt, NULL, 0, NULL, value, 0,0, min, max, default_help, XmtDOUBLE); }