1 /* Copyright (C) 1993, 1992 Nathan Sidwell */
2 /* RCS $Id: dialogs.c,v 4.6 1994/01/25 18:33:03 nathan Stable $ */
3 /*{{{  includes*/
4 #include "xmred.h"
5 #include <X11/Xaw/Dialog.h>
6 #include <X11/Shell.h>
7 #include <X11/StringDefs.h>
8 #include <X11/Xaw/Text.h>
9 #include <X11/Xaw/Label.h>
10 /*}}}*/
11 /*{{{  structs*/
12 /*{{{  typedef struct Dialog*/
13 typedef struct Dialog
14 {
15   char CONST *name;     /* shell name */
16   char CONST *prompt;   /* dialog label */
17   unsigned  input;      /* input permitted */
18   unsigned  options;    /* selections permitted */
19   unsigned  selection;  /* selection made */
20   unsigned  up;         /* popped up */
21   Widget    shell;      /* shell widget */
22   Widget    dialog;     /* dialog widget */
23   int       x;          /* warp back point */
24   int       y;          /* warp back point */
25   Widget    warp;       /* warp back widget */
26 } DIALOG;
27 /*}}}*/
28 /*{{{  typedef struct Dialog_Option*/
29 typedef struct Dialog_Option
30 {
31   char CONST *text;   /* button text */
32   unsigned  option;   /* option mask */
33 } DIALOG_OPTION;
34 /*}}}*/
35 /*}}}*/
36 /*{{{  tables*/
37 /*{{{  DIALOG_OPTION CONST dialog_options[] =*/
38 static DIALOG_OPTION CONST dialog_options[] =
39 {
40   {"ok",        DIALOG_OK},
41   {"retry",     DIALOG_RETRY},
42   {"continue",  DIALOG_CONTINUE},
43   {"default",   DIALOG_DEFAULT},
44   {"cancel",    DIALOG_CANCEL},
45   {"abort",     DIALOG_ABORT},
46   {"agree",     DIALOG_AGREE},
47   {"disagree",  DIALOG_DISAGREE},
48   {"clear",     DIALOG_CLEAR},
49   {NULL}
50 };
51 /*}}}*/
52 /*{{{  DIALOG dialogs[DIALOGS] =*/
53 static DIALOG dialogs[DIALOGS] =
54 {
55   {"file", "Enter filename", 1, DIALOG_OK | DIALOG_CANCEL | DIALOG_CLEAR},
56   {"altered", "Changes not saved", 0, DIALOG_CONTINUE | DIALOG_ABORT},
57   {"error", NULL, 1, DIALOG_RETRY | DIALOG_ABORT},
58   {"load", "Format errors", 1, DIALOG_OK},
59   {"comment", "Enter comment", 1, DIALOG_OK | DIALOG_CANCEL | DIALOG_CLEAR},
60   {"include", "Enter filename", 1,
61       DIALOG_OK | DIALOG_DEFAULT | DIALOG_CANCEL | DIALOG_CLEAR},
62   {"failed", "Operation failed", 1, DIALOG_OK},
63 };
64 /*}}}*/
65 /*}}}*/
66 /*{{{  prototypes*/
67 static VOIDFUNC dialog_action
68     PROTOARG((Widget, XEvent *, String *, Cardinal *));
69 static VOIDFUNC dialog_option PROTOARG((Widget, XtPointer, XtPointer));
70 /*}}}*/
71 /*{{{  void dialog_action(widget, event, argv, argc)*/
72 static VOIDFUNC dialog_action
73 FUNCARG((widget, event, argv, argc),
74 	Widget    widget
75 ARGSEP  XEvent    *event
76 ARGSEP  String    *argv
77 ARGSEP  Cardinal  *argc
78 )
79 /* action routine for the dialog buttons,
80  * presses all the dialog buttons matching the given arguments
81  */
82 {
83   DIALOG_OPTION CONST *optr;
84   unsigned  count;
85 
86   for(count = *argc; count--; argv++)
87     for(optr = dialog_options; optr->text; optr ++)
88       if(!strcmp(optr->text, *argv))
89 	{
90 	  dialog_option(widget, (XtPointer)optr->option, (XtPointer)NULL);
91 	  break;
92 	}
93   return;
94 }
95 /*}}}*/
96 /*{{{  void dialog_append(dialog, string)*/
97 extern VOIDFUNC dialog_append
98 FUNCARG((dialog, string),
99 	unsigned  dialog
100 ARGSEP  char CONST *string    /* string to append */
101 )
102 /* appends a string to a dialog's text box
103  */
104 {
105   XawTextBlock text;
106   Widget  widget;
107 
108   widget = XtNameToWidget(dialogs[dialog].dialog, "*value");
109   assert(widget);
110   text.firstPos = 0;
111   text.length = strlen(string);
112   text.ptr = (char *)string;
113   text.format = FMT8BIT;
114   XawTextReplace(widget, (XawTextPosition)32767,
115       (XawTextPosition)32767, &text);
116   return;
117 }
118 /*}}}*/
119 /*{{{  void dialog_option(widget, client, call)*/
120 static VOIDFUNC dialog_option
121 FUNCARG((widget, client, call),
122 	Widget  widget
123 ARGSEP  XtPointer client
124 ARGSEP  XtPointer call
125 )
126 /* callback on the dialog buttons.
127  * most of these just set an appropriate bit in the select mask
128  * For thos on the dialogs selection list, the dialog is popped down
129  * and the pointer unwarped
130  * The clear button, finds the dialog's text widget, and
131  * removes all the text from it.
132  */
133 {
134   while(widget && strcmp(XtName(widget), "dialog"))
135     widget = XtParent(widget);
136   if(!widget)
137     /* EMPTY */;
138   else if((unsigned)client == DIALOG_CLEAR)
139     {
140       Widget    text;
141 
142       text = XtNameToWidget(widget, "*value");
143       if(text)
144 	{
145 	  XawTextBlock block;
146 
147 	  block.firstPos = 0;
148 	  block.length = 0;
149 	  block.ptr = NULL;
150 	  block.format = FMT8BIT;
151 	  XawTextReplace(text, 0, 32767, &block);
152 	}
153     }
154   else
155     {
156       unsigned  count;
157       DIALOG    *dptr;
158 
159       for(dptr = dialogs, count = DIALOGS; count--; dptr++)
160 	if(dptr->dialog == widget)
161 	  {
162 	    dptr->selection |=
163 		(unsigned)client & dptr->options;
164 	    if(dptr->selection && dptr->up)
165 	      {
166 		dptr->up = 0;
167 		if(dptr->warp)
168 		  XWarpPointer(XtDisplay(dptr->shell), XtWindow(dptr->shell),
169 		      XtWindow(dptr->warp), 0, 0, 0, 0, dptr->x, dptr->y);
170 		XtPopdown(dptr->shell);
171 	      }
172 	    break;
173 	  }
174     }
175   return;
176 }
177 /*}}}*/
178 /*{{{  void dialog_popup(dialog, title, suggestion, anchor, grab)*/
179 extern VOIDFUNC dialog_popup
180 FUNCARG((dialog, title, suggestion, anchor, grab),
181 	unsigned  dialog    /* dialog to popup */
182 ARGSEP  char CONST *title   /* title or NULL */
183 ARGSEP  char CONST *suggestion  /* suggested text or NULL */
184 ARGSEP  Widget    anchor    /* widget to anchor the popup from */
185 ARGSEP  XtGrabKind grab     /* grab mode */
186 )
187 /* pops up a dialog widget 1/4 in from the top left corner of
188  * the anchor widget.
189  * Sets the warp return values if within the anchor widget, and
190  * warps the pointer to the bottom of the dialog
191  */
192 {
193   DIALOG    *dptr;
194   Position  topx, topy;
195   Dimension topw, toph;
196   Dimension w, h;
197 
198   dptr = &dialogs[dialog];
199   dptr->selection = 0;
200   dptr->warp = anchor;
201   if(anchor)
202     XtVaGetValues(anchor, XtNx, (XtArgVal)&topx, XtNy, (XtArgVal)&topy,
203 	XtNwidth, (XtArgVal)&topw, XtNheight, (XtArgVal)&toph, NULL);
204   /*{{{  setup for warp back*/
205   if(anchor)
206     {
207       Boolean   warp;
208       Window    root;
209       Window    child;
210       unsigned  mask;
211       int       rx, ry;
212 
213       warp = XQueryPointer(display.display, XtWindow(anchor),
214 	  &root, &child, &rx, &ry, &dptr->x, &dptr->y, &mask);
215       if(warp == False || dptr->x < 0 || dptr->y < 0 ||
216 	  dptr->x >= topw || dptr->y >= toph)
217 	dptr->warp = NULL;
218     }
219   /*}}}*/
220   if(title)
221     XtVaSetValues(dptr->shell, XtNtitle, (XtArgVal)title, NULL);
222   assert(dptr->input ? !!suggestion : !suggestion);
223   XtVaSetValues(dptr->dialog, XtNvalue, (XtArgVal)suggestion, NULL);
224   XtRealizeWidget(dptr->shell);
225   if(!dptr->up)
226     {
227       if(anchor)
228 	{
229 	  XtVaGetValues(dptr->shell, XtNwidth, &w, XtNheight, &h, NULL);
230 	  topx = topx + (topw - w) / 4;
231 	  topy = topy + (toph - h) / 4;
232 	  XtVaSetValues(dptr->shell, XtNx, (XtArgVal)topx,
233 	      XtNy, (XtArgVal)topy, NULL);
234 	}
235       XtPopup(dptr->shell, grab);
236       dptr->up = 1;
237     }
238   if(dptr->warp)
239     XWarpPointer(XtDisplay(dptr->shell), XtWindow(dptr->warp),
240 	XtWindow(dptr->shell), 0, 0, 0, 0, w / 2, h - 8);
241   return;
242 }
243 /*}}}*/
244 /*{{{  unsigned dialog_wait(dialog, title, label, suggestion, result)*/
245 extern unsigned dialog_wait
246 FUNCARG((dialog, title, label, suggestion, result),
247 	unsigned  dialog    /* dialog to use */
248 ARGSEP  char CONST *title   /* title or NULL */
249 ARGSEP  char CONST *label   /* label or NULL */
250 ARGSEP  char CONST *suggestion  /* initial text or NULL */
251 ARGSEP  char CONST **result   /* returned text buffer or NULL */
252 )
253 /* popup a dialog and wait for a reply.
254  * returns the text selection, this must be copied to a safe
255  * place, if you want to keep it.
256  */
257 {
258   DIALOG    *dptr;
259   unsigned  option;
260 
261   dptr = &dialogs[dialog];
262   if(label)
263     XtVaSetValues(dptr->dialog, XtNlabel, label, NULL);
264   dialog_popup(dialog, title, suggestion || !result ? suggestion : "",
265       display.toplevel, XtGrabExclusive);
266   while(!dptr->selection)
267     {
268       XEvent event;
269 
270       XtAppNextEvent(display.context, &event);
271 #ifdef DEBUGEVENTLOOP
272       fprintf(stderr, "Event %lu, Window 0x%lx\n",
273 	  (long)event.xany.type, (long)event.xany.window);
274 #endif /* DEBUGEVENTLOOP */
275       XtDispatchEvent(&event);
276     }
277   option = dptr->selection;
278   if(result)
279     {
280       char CONST *ptr;
281 
282       ptr = XawDialogGetValueString(dptr->dialog);
283       *result = ptr && *ptr ? ptr : NULL;
284     }
285   return option;
286 }
287 /*}}}*/
288 /*{{{  void install_dialogs(root)*/
289 extern VOIDFUNC install_dialogs
290 FUNCARG((root),
291 	Widget    root
292 )
293 /* install the dialog popup widgets
294  */
295 {
296   /*{{{  static XtActionsRec actions[] =*/
297   static XtActionsRec actions[] =
298   {
299     {"set-dialog-button", dialog_action},
300   };
301   /*}}}*/
302   unsigned  ix;
303   DIALOG  *dptr;
304 
305   XtAppAddActions(display.context, actions, XtNumber(actions));
306   for(dptr = &dialogs[DIALOGS - 1], ix = DIALOGS; ix--; dptr--)
307     {
308       unsigned  count;
309 
310       dptr->shell = XtVaCreatePopupShell(dptr->name,
311 	  transientShellWidgetClass, root, NULL);
312       dptr->dialog = XtVaCreateManagedWidget("dialog", dialogWidgetClass,
313 	  dptr->shell, NULL);
314       for(count = 0; count != 8; count++)
315 	if(dptr->options & (1 << count))
316 	  {
317 	    DIALOG_OPTION CONST *optr;
318 
319 	    for(optr = dialog_options; optr->text; optr++)
320 	      if(optr->option & (1 << count))
321 		{
322 		  XawDialogAddButton(dptr->dialog, optr->text,
323 		      dialog_option, (XtPointer)(1 << count));
324 		  break;
325 		}
326 	  }
327       if(dptr->input)
328 	XtVaSetValues(dptr->dialog, XtNvalue, (XtArgVal)"", NULL);
329       nadger_widget_colors(dptr->shell, (WidgetClass)NULL);
330       if(dptr->prompt)
331 	XtVaSetValues(dptr->dialog,
332 	    XtNlabel, (XtArgVal)dptr->prompt, NULL);
333     }
334   return;
335 }
336 /*}}}*/
337