]>
Commit | Line | Data |
---|---|---|
41a6b53e | 1 | /* $Header$ */ |
2 | ||
7ee9b49f | 3 | #include <stdio.h> |
698271c7 | 4 | #include <string.h> |
7ee9b49f | 5 | #include <X11/StringDefs.h> |
6 | #include <X11/IntrinsicP.h> | |
7 | #include <X11/Shell.h> | |
8 | #include <X11/Core.h> | |
9 | #include <X11/CoreP.h> | |
b80b4770 | 10 | #include <X11/CompositeP.h> |
7ee9b49f | 11 | #include <Xm/Xm.h> |
12 | #include <Xm/BulletinB.h> | |
13 | #include <Xm/Label.h> | |
14 | #include <Xm/Text.h> | |
41a6b53e | 15 | #include <Xm/TextP.h> |
7ee9b49f | 16 | #include <Xm/PushB.h> |
17 | #include <Xm/PushBG.h> | |
18 | #include <Xm/CascadeB.h> | |
19 | #include <Xm/ToggleB.h> | |
20 | #include <Xm/ToggleBG.h> | |
21 | #include <Xm/RowColumn.h> | |
22 | #include <Xm/Separator.h> | |
3583baaa | 23 | #include <Xm/Traversal.h> |
7ee9b49f | 24 | #include "mmoira.h" |
25 | ||
892c98b2 | 26 | static char rcsid[] = "$Header$"; |
27 | ||
41a6b53e | 28 | #ifndef MAX |
7ee9b49f | 29 | #define MAX(a,b) ((a > b) ? a : b) |
41a6b53e | 30 | #endif |
31 | #ifndef MIN | |
ecb7d146 | 32 | #define MIN(a,b) ((a < b) ? a : b) |
41a6b53e | 33 | #endif |
7ee9b49f | 34 | |
4fa286c6 | 35 | int hpad = 10; |
36 | int vpad = 5; | |
7ee9b49f | 37 | |
7ee9b49f | 38 | void manage_widget(); |
39 | Widget CreateForm(); | |
40 | Widget CreateMenu(); | |
41 | Widget BuildMenuTree(); | |
ecb7d146 | 42 | Widget MakeRadioField(); |
892c98b2 | 43 | int button_callback(); |
ecb7d146 | 44 | void radio_callback(); |
ecb7d146 | 45 | void string_callback(); |
892c98b2 | 46 | void boolean_callback(); |
7ee9b49f | 47 | void menu_callback(); |
3583baaa | 48 | void newvalue(); |
41a6b53e | 49 | void MoiraFocusOut(); |
3583baaa | 50 | EntryForm *WidgetToForm(); |
7ee9b49f | 51 | |
4fa286c6 | 52 | extern void UpdateForm(); |
892c98b2 | 53 | extern int PopupErrorMessage(); |
54 | extern void PopupHelpWindow(); | |
55 | extern int AppendToLog(); | |
892c98b2 | 56 | extern void MakeWatchCursor(); |
57 | extern void MakeNormalCursor(); | |
58 | extern Widget SetupLogWidget(); | |
7ee9b49f | 59 | |
41a6b53e | 60 | static XtActionsRec myactions[] = { |
61 | { "MoiraFocusOut", MoiraFocusOut }, | |
62 | }; | |
63 | ||
892c98b2 | 64 | |
65 | void | |
66 | manage_widget(w, widget, call_data) | |
67 | Widget w, widget; | |
68 | XmAnyCallbackStruct *call_data; | |
ecb7d146 | 69 | { |
892c98b2 | 70 | XtManageChild(widget); |
71 | } | |
ecb7d146 | 72 | |
892c98b2 | 73 | int |
b2d21e59 | 74 | button_callback(w, client_data, call_data) |
75 | Widget w; | |
76 | EntryForm *client_data; | |
892c98b2 | 77 | XmAnyCallbackStruct *call_data; |
78 | { | |
b2d21e59 | 79 | XtUnmanageChild(client_data->formpointer); |
892c98b2 | 80 | } |
81 | ||
82 | ||
83 | Widget | |
84 | BuildMenuTree(topW, spec) | |
85 | Widget topW; | |
86 | MenuItem *spec; | |
87 | { | |
88 | return (CreateMenu(topW, spec->submenu, XmHORIZONTAL)); | |
ecb7d146 | 89 | } |
90 | ||
7ee9b49f | 91 | /* |
92 | ** Read the specification and put up a menu to match... | |
7ee9b49f | 93 | */ |
94 | ||
95 | Widget | |
96 | CreateMenu(parent, spec, orientation) | |
97 | Widget parent; | |
98 | MenuItem **spec; | |
99 | int orientation; | |
100 | { | |
101 | Widget menuparent; | |
102 | MenuItem *curmenuitem; | |
103 | Widget childbutton, childmenu; | |
104 | Arg wargs[10]; | |
105 | int n; | |
106 | XmString label; /* !@#$%^ compound string required */ | |
7ee9b49f | 107 | |
108 | label = XmStringCreate( "Complete junk", XmSTRING_DEFAULT_CHARSET); | |
109 | ||
110 | n = 0; | |
7ee9b49f | 111 | XtSetArg(wargs[n], XmNlabelString, label); n++; |
7ee9b49f | 112 | |
892c98b2 | 113 | if (orientation == XmHORIZONTAL) { |
114 | XtSetArg(wargs[n], XmNspacing, 5); n++; | |
115 | menuparent = XmCreateMenuBar( parent, "randommenu", | |
116 | wargs, n); | |
117 | XtManageChild(menuparent); | |
118 | } | |
ecb7d146 | 119 | else |
120 | menuparent = XmCreatePulldownMenu(parent, "randommenu", | |
121 | wargs, n); | |
122 | ||
7ee9b49f | 123 | for ( curmenuitem = (*spec); |
124 | curmenuitem; | |
125 | spec++, curmenuitem = (*spec)) { | |
126 | ||
127 | #ifdef DEBUG | |
128 | printf ("Making entry: %s\n", curmenuitem->label); | |
129 | #endif | |
130 | label = XmStringCreate( curmenuitem->label, | |
131 | XmSTRING_DEFAULT_CHARSET); | |
7ee9b49f | 132 | n = 0; |
133 | XtSetArg(wargs[n], XmNlabelString, label); n++; | |
3583baaa | 134 | if (curmenuitem->accel) { |
135 | XtSetArg(wargs[n], XmNmnemonic, *(curmenuitem->accel)); n++; | |
136 | } | |
7ee9b49f | 137 | |
7ee9b49f | 138 | if (curmenuitem->submenu) { |
139 | #ifdef DEBUG | |
140 | printf ("It has a submenu, which I'm recursing on...\n"); | |
141 | #endif | |
ecb7d146 | 142 | childmenu = CreateMenu( menuparent, |
143 | curmenuitem->submenu, | |
144 | XmVERTICAL); | |
7ee9b49f | 145 | XtSetArg(wargs[n], XmNsubMenuId, childmenu); n++; |
146 | ||
147 | childbutton = XtCreateManagedWidget( "child", | |
148 | xmCascadeButtonWidgetClass, | |
149 | menuparent, wargs, n); | |
7ee9b49f | 150 | |
7ee9b49f | 151 | } |
152 | ||
153 | else { | |
ecb7d146 | 154 | childbutton = XtCreateManagedWidget( "child", |
155 | xmPushButtonGadgetClass, | |
156 | menuparent, wargs, n); | |
157 | ||
7ee9b49f | 158 | XtAddCallback( childbutton, |
159 | XmNactivateCallback, | |
160 | menu_callback, curmenuitem); | |
161 | } | |
162 | } | |
7ee9b49f | 163 | |
ecb7d146 | 164 | return (menuparent); |
7ee9b49f | 165 | } |
166 | ||
7ee9b49f | 167 | /* |
168 | ** Read the specification and put up a form to match... | |
169 | */ | |
170 | ||
171 | Widget | |
172 | CreateForm(parent, spec) | |
173 | Widget parent; | |
174 | EntryForm *spec; | |
175 | { | |
ecb7d146 | 176 | Widget bb; |
7ee9b49f | 177 | Arg wargs[10]; |
ecb7d146 | 178 | int n; |
7ee9b49f | 179 | XmString label; /* compound string required */ |
180 | Dimension height_so_far = 0, width_so_far = 0; | |
181 | Dimension height, width; | |
182 | Widget titleW, instructionW; | |
183 | Position x, y; | |
184 | Widget shellparent; | |
185 | ||
ecb7d146 | 186 | if (spec->formpointer) { |
4fa286c6 | 187 | UpdateForm(spec); |
ecb7d146 | 188 | return(spec->formpointer); |
189 | } | |
7ee9b49f | 190 | |
b2d21e59 | 191 | height_so_far = vpad; |
192 | ||
7ee9b49f | 193 | #define GETSIZE(foo) n = 0; \ |
194 | XtSetArg(wargs[n], XtNwidth, &width); n++; \ | |
195 | XtSetArg(wargs[n], XtNheight, &height); n++; \ | |
196 | XtGetValues (foo, wargs, n); \ | |
197 | ||
198 | #define STORESIZE if (width > width_so_far) width_so_far = width;\ | |
4fa286c6 | 199 | height_so_far += height + vpad; |
7ee9b49f | 200 | |
201 | ||
202 | n = 0; | |
4fa286c6 | 203 | XtSetArg(wargs[n], XmNautoUnmanage, False); n++; |
41a6b53e | 204 | bb = XmCreateBulletinBoardDialog(parent, spec->formname, wargs, n); |
3583baaa | 205 | MapWidgetToForm(bb, spec); |
ecb7d146 | 206 | |
ecb7d146 | 207 | spec->formpointer = bb; |
7ee9b49f | 208 | |
4fa286c6 | 209 | #ifdef FORMTITLES |
7ee9b49f | 210 | label = XmStringCreate(spec->formname, XmSTRING_DEFAULT_CHARSET); |
211 | n = 0; | |
212 | XtSetArg(wargs[n], XmNlabelString, label); n++; | |
213 | XtSetArg(wargs[n], XtNx, 0); n++; | |
214 | XtSetArg(wargs[n], XtNy, 0); n++; | |
215 | titleW = XtCreateManagedWidget( "title", | |
216 | xmLabelWidgetClass, | |
217 | bb, wargs, n); | |
218 | GETSIZE(titleW); | |
219 | STORESIZE; | |
4fa286c6 | 220 | #endif |
7ee9b49f | 221 | |
222 | label = XmStringCreate(spec->instructions, XmSTRING_DEFAULT_CHARSET); | |
223 | n = 0; | |
224 | XtSetArg(wargs[n], XmNlabelString, label); n++; | |
225 | XtSetArg(wargs[n], XtNx, 0); n++; | |
226 | XtSetArg(wargs[n], XtNy, height_so_far); n++; | |
b2d21e59 | 227 | instructionW = XtCreateManagedWidget( "instructions", |
7ee9b49f | 228 | xmLabelWidgetClass, |
229 | bb, wargs, n); | |
230 | GETSIZE(instructionW); | |
231 | STORESIZE; | |
232 | ||
233 | height = height_so_far; | |
234 | width = width_so_far; | |
ecb7d146 | 235 | MakeInputLines(bb, &height, &width, spec); |
7ee9b49f | 236 | STORESIZE; |
237 | ||
238 | height = height_so_far; | |
239 | width = width_so_far; | |
ecb7d146 | 240 | MakeButtons(bb, &height, &width, spec); |
7ee9b49f | 241 | STORESIZE; |
242 | ||
243 | /* | |
244 | ** Center the title of the form | |
245 | */ | |
b2d21e59 | 246 | #ifdef FORMTITLES |
7ee9b49f | 247 | n = 0; |
248 | XtSetArg(wargs[n], XtNwidth, &width); n++; | |
249 | XtGetValues (titleW, wargs, n); | |
250 | ||
251 | x = (width_so_far - width) / 2; | |
252 | ||
253 | n = 0; | |
254 | XtSetArg(wargs[n], XtNx, x); n++; | |
255 | XtSetValues (titleW, wargs, n); | |
4fa286c6 | 256 | #endif |
b2d21e59 | 257 | n = 0; |
258 | XtSetArg(wargs[n], XtNwidth, &width); n++; | |
259 | XtGetValues (instructionW, wargs, n); | |
260 | ||
261 | x = (width_so_far - width) / 2; | |
262 | ||
263 | n = 0; | |
264 | XtSetArg(wargs[n], XtNx, x); n++; | |
265 | XtSetValues (instructionW, wargs, n); | |
266 | ||
7ee9b49f | 267 | return((Widget) bb); |
268 | } | |
269 | ||
270 | /* | |
271 | ** Pheight and pwidth start with the values-to-date of the bboard so far. | |
272 | ** Return your height and width in them when you're done. | |
273 | ** | |
274 | ** Positioning the widgets happens in two phases: | |
275 | ** First, we set their y-positions as we create them. | |
276 | ** After they're created, we go back and adjust the x-positions | |
277 | ** according to the widest left side noted. | |
278 | */ | |
279 | ||
ecb7d146 | 280 | MakeInputLines(parent, pheight, pwidth, spec) |
7ee9b49f | 281 | Widget parent; |
282 | Dimension *pheight; | |
283 | Dimension *pwidth; | |
ecb7d146 | 284 | EntryForm *spec; |
7ee9b49f | 285 | { |
286 | UserPrompt *current; | |
287 | XmString label; /* compound string required */ | |
288 | Arg wargs[10]; | |
289 | int i, n; | |
290 | Widget child; | |
291 | Dimension width, height, maxleftwidth = 0, maxrightwidth = 0; | |
292 | Dimension localy, leftheight = 0, rightheight = 0; | |
ecb7d146 | 293 | UserPrompt **myinputlines = spec->inputlines; |
7ee9b49f | 294 | int foo = 30; |
295 | Widget children[20]; | |
41a6b53e | 296 | static XtTranslations trans = NULL; |
7ee9b49f | 297 | |
298 | for ( current = (*myinputlines), localy = 0, i = 0; | |
299 | current; | |
300 | myinputlines++, current = (*myinputlines), i++) { | |
301 | ||
302 | ||
303 | #ifdef DEBUG | |
304 | printf ("Making entry %d: %s of type %d\n", | |
305 | i, current->prompt, current->type); | |
306 | #endif | |
307 | /* | |
308 | ** First, make the prompt | |
309 | */ | |
3583baaa | 310 | if (current->type == FT_KEYWORD) { |
311 | char *p; | |
312 | ||
698271c7 | 313 | p = strchr(current->prompt, '|'); |
3583baaa | 314 | if (p) { |
315 | *p++ = 0; | |
316 | current->keyword_name = p; | |
317 | } | |
318 | } | |
319 | ||
7ee9b49f | 320 | label = XmStringCreate( current->prompt, |
321 | XmSTRING_DEFAULT_CHARSET); | |
322 | n = 0; | |
323 | XtSetArg(wargs[n], XmNlabelString, label); n++; | |
324 | XtSetArg(wargs[n], XtNy, localy + *pheight); n++; | |
325 | child = XtCreateManagedWidget( "prompt", | |
326 | xmLabelWidgetClass, | |
327 | parent, wargs, n); | |
328 | ||
329 | GETSIZE(child); | |
330 | leftheight = height; | |
331 | if (width > maxleftwidth) | |
332 | maxleftwidth = width; | |
333 | ||
3583baaa | 334 | if (current->type == FT_KEYWORD && current->keyword_name) { |
335 | label = XmStringCreate("add new value", | |
336 | XmSTRING_DEFAULT_CHARSET); | |
337 | n = 0; | |
338 | XtSetArg(wargs[n], XmNlabelString, label); n++; | |
339 | XtSetArg(wargs[n], XtNy, localy + *pheight + height); n++; | |
340 | XtSetArg(wargs[n], XtNx, height); n++; | |
341 | child = XtCreateManagedWidget("newvalue", | |
342 | xmPushButtonWidgetClass, | |
343 | parent, wargs, n); | |
344 | XtAddCallback(child, XmNactivateCallback, | |
345 | newvalue, current); | |
346 | ||
347 | GETSIZE(child); | |
348 | leftheight += height; | |
349 | if (width + height > maxleftwidth) | |
350 | maxleftwidth = width + height; | |
351 | } | |
7ee9b49f | 352 | /* |
353 | ** Second, make the input widget | |
354 | */ | |
355 | n = 0; | |
356 | XtSetArg(wargs[n], XtNy, localy + *pheight); n++; | |
ecb7d146 | 357 | XtSetArg(wargs[n], XmNtraversalOn, True); n++; |
7ee9b49f | 358 | XtSetArg(wargs[n], XtNsensitive, |
359 | !(current->insensitive)); n++; | |
360 | switch (current->type) { | |
361 | case FT_STRING: | |
b2d21e59 | 362 | children[i] = XtCreateManagedWidget( "textwidget", |
7ee9b49f | 363 | xmTextWidgetClass, |
364 | parent, wargs, n); | |
b2d21e59 | 365 | XtAddCallback( children[i], XmNvalueChangedCallback, |
ecb7d146 | 366 | string_callback, current); |
41a6b53e | 367 | if (trans == NULL) { |
368 | XtAppAddActions(XtWidgetToApplicationContext(children[i]), | |
369 | myactions, XtNumber(myactions)); | |
370 | ||
111b5809 | 371 | trans = XtParseTranslationTable(resources.text_trans); |
41a6b53e | 372 | } |
373 | XtOverrideTranslations(children[i], trans); | |
7ee9b49f | 374 | if (current->returnvalue.stringvalue) { |
375 | XmTextSetString (children[i], current->returnvalue.stringvalue); | |
376 | } | |
377 | GETSIZE (children[i]); | |
378 | rightheight = height; | |
379 | if (width > maxrightwidth) | |
380 | maxrightwidth = width; | |
381 | break; | |
382 | ||
383 | case FT_BOOLEAN: | |
b2d21e59 | 384 | XtSetArg(wargs[n], XmNset, |
385 | current->returnvalue.booleanvalue ? True : False); n++; | |
ecb7d146 | 386 | |
387 | if (current->returnvalue.booleanvalue) | |
388 | label = XmStringCreate( "(True)", XmSTRING_DEFAULT_CHARSET); | |
389 | else | |
390 | label = XmStringCreate( "(False)", XmSTRING_DEFAULT_CHARSET); | |
7ee9b49f | 391 | XtSetArg(wargs[n], XmNlabelString, label); n++; |
392 | ||
393 | children[i] = XtCreateManagedWidget( "ignore this", | |
394 | xmToggleButtonWidgetClass, | |
395 | parent, wargs, n); | |
396 | ||
397 | XtAddCallback( children[i], XmNvalueChangedCallback, | |
ecb7d146 | 398 | boolean_callback, current); |
7ee9b49f | 399 | |
400 | GETSIZE (children[i]); | |
401 | rightheight = height; | |
402 | if (width > maxrightwidth) | |
403 | maxrightwidth = width; | |
404 | break; | |
405 | ||
406 | case FT_KEYWORD: | |
ecb7d146 | 407 | children[i] = |
3583baaa | 408 | MakeRadioField(parent, current, |
409 | &rightheight, spec); | |
ecb7d146 | 410 | XtManageChild(children[i]); |
411 | XtSetValues(children[i], wargs, n); | |
7ee9b49f | 412 | GETSIZE (children[i]); |
413 | if (width > maxrightwidth) | |
414 | maxrightwidth = width; | |
415 | break; | |
416 | ||
417 | default: | |
418 | printf ("Sorry, don't recognize that type\n"); | |
419 | break; | |
420 | } | |
ecb7d146 | 421 | XmAddTabGroup(children[i]); |
3583baaa | 422 | MapWidgetToForm(children[i], spec); |
423 | current->parent = (caddr_t) spec; | |
424 | ||
4fa286c6 | 425 | current->mywidget = children[i]; |
7ee9b49f | 426 | |
4fa286c6 | 427 | localy += MAX(rightheight, leftheight) + vpad; |
7ee9b49f | 428 | } |
429 | ||
430 | /* | |
431 | ** Now slide the input widgets right as far as the widest prompt. | |
432 | */ | |
433 | n = 0; | |
4fa286c6 | 434 | XtSetArg(wargs[n], XtNx, maxleftwidth + hpad); n++; |
7ee9b49f | 435 | for (; i; i--) |
436 | XtSetValues (children[i - 1], wargs, n); | |
437 | ||
4fa286c6 | 438 | *pheight = localy - vpad; |
439 | *pwidth = maxleftwidth + maxrightwidth + hpad; | |
7ee9b49f | 440 | } |
441 | ||
442 | /* | |
443 | ** All the junk about keeping track of the sum of the children's heights | |
444 | ** is because the !#$% RowColumn widget doesn't sum them for us, NOR | |
ecb7d146 | 445 | ** does it accept SetValues on its XtNHeight! Thanks, Motif! |
7ee9b49f | 446 | */ |
447 | ||
ecb7d146 | 448 | Widget |
3583baaa | 449 | MakeRadioField(parent, prompt, pheight, spec) |
7ee9b49f | 450 | Widget parent; |
451 | UserPrompt *prompt; | |
452 | Dimension *pheight; | |
3583baaa | 453 | EntryForm *spec; |
7ee9b49f | 454 | { |
41a6b53e | 455 | Widget radioparent, child = NULL; |
7ee9b49f | 456 | char *current; |
457 | Arg wargs[10]; | |
ecb7d146 | 458 | int count, n; |
459 | XmString label; /* accursed compound string required */ | |
7ee9b49f | 460 | Dimension height, width; |
41a6b53e | 461 | char **keywords, *null[2]; |
7ee9b49f | 462 | |
4fa286c6 | 463 | if (!prompt->keywords) { |
7ee9b49f | 464 | fprintf (stderr, "Warning: No list of keywords for widget\n"); |
41a6b53e | 465 | prompt->keywords = null; |
466 | null[0] = NULL; | |
7ee9b49f | 467 | } |
ecb7d146 | 468 | for ( count = 0, keywords = prompt->keywords; |
469 | *keywords; | |
470 | keywords++, count++); | |
471 | ||
472 | /* | |
473 | ** Although the XmNnumColumns resource is documented as actually | |
474 | ** representing the number of _rows_ when XmNorientation is set to XmVERTICAL, | |
475 | ** it doesn't. So I need to count the items myself and manually set the | |
476 | ** number of columns to get a maximum of five rows. There's no XmNnumRows | |
477 | ** resource. Thanks, Motif! | |
478 | */ | |
479 | ||
480 | n = 0; | |
892c98b2 | 481 | XtSetArg(wargs[n], XmNspacing, 0); n++; |
482 | ||
ecb7d146 | 483 | if (count > 5) { |
b2d21e59 | 484 | XtSetArg(wargs[n], XmNnumColumns, 1 + (count-1) / 5); n++; |
ecb7d146 | 485 | XtSetArg(wargs[n], XmNorientation, XmVERTICAL); n++; |
486 | XtSetArg(wargs[n], XmNpacking, XmPACK_COLUMN); n++; | |
487 | } | |
ecb7d146 | 488 | radioparent = XmCreateRadioBox(parent, "radio", wargs, n); |
489 | ||
490 | keywords = prompt->keywords; | |
7ee9b49f | 491 | for (current=(*keywords); current; keywords++, current=(*keywords)) { |
492 | n = 0; | |
493 | label = XmStringCreate(current, XmSTRING_DEFAULT_CHARSET); | |
494 | XtSetArg(wargs[n], XmNlabelString, label); n++; | |
b2d21e59 | 495 | if ((prompt->returnvalue.stringvalue) && |
496 | (!strcmp (current, prompt->returnvalue.stringvalue))) { | |
7ee9b49f | 497 | XtSetArg(wargs[n], XmNset, True); n++; |
498 | } | |
499 | else { | |
500 | XtSetArg(wargs[n], XmNset, False); n++; | |
501 | } | |
502 | child = XtCreateManagedWidget( current, | |
892c98b2 | 503 | xmToggleButtonWidgetClass, |
ecb7d146 | 504 | radioparent, wargs, n); |
3583baaa | 505 | MapWidgetToForm(child, spec); |
7ee9b49f | 506 | |
507 | XtAddCallback( child, XmNvalueChangedCallback, | |
508 | radio_callback, prompt); | |
509 | ||
7ee9b49f | 510 | } |
511 | /* | |
ecb7d146 | 512 | ** Assume all child widgets are the same height. Increase height by |
513 | ** five times this, or the actual number of children, whichever is lesser. | |
514 | */ | |
515 | ||
41a6b53e | 516 | if (child) { |
517 | GETSIZE (child); | |
518 | } else | |
519 | height = 10; | |
b2d21e59 | 520 | *pheight = (height * MIN(5, count)) + vpad; |
ecb7d146 | 521 | |
ecb7d146 | 522 | return(radioparent); |
7ee9b49f | 523 | } |
524 | ||
41a6b53e | 525 | |
526 | /* This is called when the list of keywords changes. The old radio box | |
527 | * will be destroyed and a new one created. | |
528 | */ | |
529 | ||
530 | RemakeRadioField(form, field) | |
531 | EntryForm *form; | |
532 | int field; | |
533 | { | |
534 | Dimension x, y, parent_y, oldheight, newheight; | |
535 | Arg wargs[4]; | |
536 | Widget w; | |
41a6b53e | 537 | static XtTranslations trans = NULL; |
538 | extern char form_override_table[]; | |
539 | int i; | |
540 | ||
541 | XtSetArg(wargs[0], XtNx, &x); | |
542 | XtSetArg(wargs[1], XtNy, &y); | |
543 | XtSetArg(wargs[2], XtNheight, &oldheight); | |
544 | XtGetValues(form->inputlines[field]->mywidget, wargs, 3); | |
545 | XtUnmanageChild(form->inputlines[field]->mywidget); | |
546 | form->inputlines[field]->mywidget = w = | |
547 | MakeRadioField(form->formpointer, form->inputlines[field], | |
548 | &newheight, form); | |
549 | XtSetArg(wargs[0], XtNx, x); | |
550 | XtSetArg(wargs[1], XtNy, y); | |
551 | XtSetValues(w, wargs, 2); | |
552 | MapWidgetToForm(w, form); | |
553 | XmAddTabGroup(w); | |
554 | if (newheight > oldheight) { | |
41a6b53e | 555 | parent_y = y; |
b80b4770 | 556 | for (i = 0; i < NumChildren(form->formpointer); i++) { |
41a6b53e | 557 | XtSetArg(wargs[0], XtNy, &y); |
b80b4770 | 558 | XtGetValues(NthChild(form->formpointer, i), wargs, 1); |
41a6b53e | 559 | if (y > parent_y) { |
560 | y = (y + newheight) - oldheight; | |
561 | XtSetArg(wargs[0], XtNy, y); | |
b80b4770 | 562 | XtSetValues(NthChild(form->formpointer, i), wargs, 1); |
41a6b53e | 563 | } |
564 | } | |
565 | } | |
566 | ||
567 | if (trans == NULL) | |
111b5809 | 568 | trans = XtParseTranslationTable(resources.form_trans); |
41a6b53e | 569 | XtOverrideTranslations(w, trans); |
b80b4770 | 570 | for (i = 0; i < NumChildren(w); i++) |
571 | XtOverrideTranslations(NthChild(w, i), trans); | |
41a6b53e | 572 | |
573 | XtManageChild(w); | |
574 | } | |
575 | ||
576 | ||
ecb7d146 | 577 | MakeButtons(parent, pheight, pwidth, spec) |
7ee9b49f | 578 | Widget parent; |
579 | Dimension *pheight; | |
580 | Dimension *pwidth; | |
ecb7d146 | 581 | EntryForm *spec; |
7ee9b49f | 582 | { |
583 | BottomButton *current; | |
584 | XmString label; /* compound string required */ | |
585 | Arg wargs[10]; | |
586 | int i, n; | |
587 | Dimension newwidth, width = 25; | |
588 | Widget newbutton; | |
ecb7d146 | 589 | BottomButton **buttons = spec->buttons; |
7ee9b49f | 590 | |
4fa286c6 | 591 | *pheight += vpad; |
592 | ||
7ee9b49f | 593 | n = 0; |
594 | XtSetArg(wargs[n], XtNy, *pheight); n++; | |
595 | XtSetArg(wargs[n], XtNx, 0); n++; | |
596 | XtSetArg(wargs[n], XtNwidth, *pwidth); n++; | |
597 | XtCreateManagedWidget( "separator", | |
598 | xmSeparatorWidgetClass, | |
599 | parent, wargs, n); | |
4fa286c6 | 600 | *pheight += vpad; |
7ee9b49f | 601 | |
602 | for ( current=(*buttons); | |
603 | current; | |
604 | buttons++, current=(*buttons)) { | |
605 | ||
606 | #ifdef DEBUG | |
607 | printf ("Making a button labeled %s\n", current->label); | |
608 | #endif | |
609 | label = XmStringCreate( current->label, | |
610 | XmSTRING_DEFAULT_CHARSET); | |
611 | n = 0; | |
612 | XtSetArg(wargs[n], XtNy, (*pheight)); n++; | |
613 | XtSetArg(wargs[n], XtNx, width); n++; | |
614 | XtSetArg(wargs[n], XmNlabelString, label); n++; | |
615 | ||
616 | newbutton = XtCreateManagedWidget( current->label, | |
617 | xmPushButtonWidgetClass, | |
618 | parent, wargs, n); | |
619 | ||
5bcb5e58 | 620 | XtAddCallback(newbutton, XmNactivateCallback, |
621 | (XtCallbackProc) current->returnfunction, | |
622 | spec); | |
7ee9b49f | 623 | n = 0; |
624 | XtSetArg(wargs[n], XtNwidth, &newwidth); n++; | |
625 | XtGetValues (newbutton, wargs, n); | |
626 | ||
4fa286c6 | 627 | width += (newwidth + hpad); |
7ee9b49f | 628 | } |
629 | ||
630 | (*pheight) += 100; | |
631 | } | |
632 | ||
ecb7d146 | 633 | void |
7ee9b49f | 634 | radio_callback(w, client_data, call_data) |
635 | Widget w; | |
636 | XmAnyCallbackStruct *client_data; | |
637 | XmAnyCallbackStruct *call_data; | |
638 | { | |
639 | Arg wargs[10]; | |
ecb7d146 | 640 | int n; |
641 | Boolean is_set; | |
7ee9b49f | 642 | |
643 | UserPrompt *prompt = (UserPrompt *) client_data; | |
644 | ||
7ee9b49f | 645 | n = 0; |
ecb7d146 | 646 | XtSetArg(wargs[n], XmNset, &is_set); n++; |
7ee9b49f | 647 | XtGetValues (w, wargs, n); |
648 | ||
ecb7d146 | 649 | if (!is_set) |
650 | return; | |
7ee9b49f | 651 | |
652 | /* | |
ecb7d146 | 653 | ** Since Motif insists on using !@#$% Compound Strings as the text for |
654 | ** its label widgets, but doesn't provide a way of getting a char* back | |
655 | ** from a !@#$% Compound String, I can't retrieve the label of the button | |
656 | ** that was hit. | |
657 | ** | |
658 | ** Fortunately, I was smart enough to use the button label as the name | |
659 | ** of the widget, and I can extract it via XtName(). Thanks, Motif! | |
660 | */ | |
b2d21e59 | 661 | if (prompt->returnvalue.stringvalue && |
662 | (strcmp(prompt->returnvalue.stringvalue, XtName(w)))) { | |
892c98b2 | 663 | strcpy(prompt->returnvalue.stringvalue, XtName(w)); |
3583baaa | 664 | if (prompt->valuechanged) |
665 | (*prompt->valuechanged)(WidgetToForm(w), prompt); | |
892c98b2 | 666 | } |
7ee9b49f | 667 | |
ecb7d146 | 668 | } |
669 | ||
670 | void | |
671 | boolean_callback(w, client_data, call_data) | |
672 | Widget w; | |
673 | XmAnyCallbackStruct *client_data; | |
674 | XmAnyCallbackStruct *call_data; | |
675 | { | |
676 | Arg wargs[10]; | |
677 | int n; | |
678 | Boolean is_set; | |
679 | UserPrompt *current = (UserPrompt *)client_data; | |
680 | XmString label; | |
681 | ||
682 | n = 0; | |
683 | XtSetArg(wargs[n], XmNset, &is_set); n++; | |
684 | XtGetValues (w, wargs, n); | |
685 | ||
686 | current->returnvalue.booleanvalue = is_set; | |
7ee9b49f | 687 | |
ecb7d146 | 688 | if (is_set) |
689 | label = XmStringCreate( "(True)", XmSTRING_DEFAULT_CHARSET); | |
690 | else | |
691 | label = XmStringCreate( "(False)", XmSTRING_DEFAULT_CHARSET); | |
692 | n = 0; | |
693 | XtSetArg(wargs[n], XmNlabelString, label); n++; | |
694 | XtSetValues (w, wargs, n); | |
695 | ||
3583baaa | 696 | if (current->valuechanged) |
697 | (*current->valuechanged)(WidgetToForm(w), current); | |
698 | ||
ecb7d146 | 699 | #if DEBUG |
700 | printf ("boolean_callback: button %x is %s\n", | |
701 | w, (is_set ? "True" : "False")); | |
702 | #endif | |
7ee9b49f | 703 | } |
704 | ||
705 | void | |
706 | menu_callback(w, client_data, call_data) | |
707 | Widget w; | |
708 | XmAnyCallbackStruct *client_data; | |
709 | XmAnyCallbackStruct *call_data; | |
710 | { | |
711 | MenuItem *itemhit = (MenuItem *) client_data; | |
712 | ||
b2d21e59 | 713 | /* printf ("menu_callback: item '%s', op %d and string '%s'\n", |
714 | itemhit->label, | |
715 | itemhit->operation, | |
716 | itemhit->form); | |
717 | XtManageChild(entryformwidget); | |
718 | */ | |
7ee9b49f | 719 | MoiraMenuRequest(itemhit); |
ecb7d146 | 720 | } |
7ee9b49f | 721 | |
892c98b2 | 722 | |
ecb7d146 | 723 | void |
724 | string_callback(w, client_data, call_data) | |
725 | Widget w; | |
726 | XmAnyCallbackStruct *client_data; | |
727 | XmAnyCallbackStruct *call_data; | |
728 | { | |
729 | UserPrompt *current = (UserPrompt *)client_data; | |
730 | char *newvalue; | |
731 | ||
732 | newvalue = XmTextGetString(w); | |
733 | ||
892c98b2 | 734 | if (strcmp(current->returnvalue.stringvalue, newvalue)) { |
b2d21e59 | 735 | /* printf ("Replacing old value of selection, '%s', with '%s'\n", |
892c98b2 | 736 | current->returnvalue.stringvalue, |
737 | newvalue); | |
41a6b53e | 738 | strcpy(current->returnvalue.stringvalue, newvalue); |
3583baaa | 739 | if (current->valuechanged) |
740 | (*current->valuechanged)(WidgetToForm(w), current); | |
41a6b53e | 741 | */ } |
ecb7d146 | 742 | XtFree(newvalue); |
7ee9b49f | 743 | } |
3583baaa | 744 | |
745 | ||
41a6b53e | 746 | void MoiraFocusOut(w, event, p, n) |
747 | Widget w; | |
748 | XEvent *event; | |
749 | String *p; | |
750 | Cardinal *n; | |
751 | { | |
752 | char *newvalue; | |
753 | UserPrompt *current = NULL; | |
754 | EntryForm *f; | |
755 | XmTextRec *tr = (XmTextRec *)w; | |
756 | int i; | |
757 | ||
2528015e | 758 | if (!tr || tr->core.self != w || tr->core.widget_class != xmTextWidgetClass) |
41a6b53e | 759 | return; |
760 | newvalue = XmTextGetString(w); | |
761 | f = WidgetToForm(w); | |
762 | for (i = 0; f->inputlines[i]; i++) | |
763 | if (f->inputlines[i]->mywidget == w) | |
764 | current = f->inputlines[i]; | |
765 | if (current == NULL) { | |
766 | fprintf(stderr, "Couldn't find prompt structure!\n"); | |
767 | return; | |
768 | } | |
769 | ||
770 | if (strcmp(current->returnvalue.stringvalue, newvalue)) { | |
771 | strcpy(current->returnvalue.stringvalue, newvalue); | |
772 | if (current->valuechanged) | |
773 | (*current->valuechanged)(f, current); | |
774 | } | |
775 | XtFree(newvalue); | |
776 | } | |
777 | ||
778 | ||
3583baaa | 779 | void |
780 | newvalue(w, client_data, call_data) | |
781 | Widget w; | |
782 | XmAnyCallbackStruct *client_data; | |
783 | XmAnyCallbackStruct *call_data; | |
784 | { | |
785 | UserPrompt *current = (UserPrompt *)client_data; | |
786 | EntryForm *form, *f; | |
787 | int i; | |
f9c6085e | 788 | static MenuItem mi; |
3583baaa | 789 | |
790 | if (current->keyword_name == NULL) { | |
791 | PopupErrorMessage("Sorry, that keyword cannot be changed.", NULL); | |
792 | return; | |
793 | } | |
794 | form = (EntryForm *)current->parent; | |
795 | for (i = 0; form->inputlines[i]; i++) | |
796 | if (form->inputlines[i] == current) | |
797 | break; | |
798 | f = GetAndClearForm("add_new_value"); | |
f9c6085e | 799 | mi.operation = MM_NEW_VALUE; |
800 | mi.query = "add_alias"; | |
801 | mi.argc = 3; | |
802 | mi.form = form->formname; | |
803 | mi.accel = (char *) i; | |
804 | f->menu = &mi; | |
3583baaa | 805 | f->extrastuff = current->keyword_name; |
806 | DisplayForm(f); | |
807 | } | |
808 | ||
809 | ||
810 | /* WARNING: This routine uses Motif internal undocumented routines. | |
811 | * It was the only way to get carriage return to Do The Right Thing. | |
812 | * If you are in a single-item tab group, this routine will call | |
813 | * MoiraFormComplete() (same as pressing OK on the bottom of the form). | |
814 | * otherwise, it advances the focus the same as pressing TAB. | |
815 | */ | |
816 | ||
817 | void EnterPressed(w, event, argv, count) | |
818 | Widget w; | |
819 | XEvent *event; | |
820 | char **argv; | |
821 | Cardinal *count; | |
822 | { | |
823 | Widget next; | |
824 | EntryForm *form; | |
825 | ||
826 | next = _XmFindNextTabGroup(w); | |
827 | if (next == w) { | |
41a6b53e | 828 | MoiraFocusOut(w, event, argv, count); |
3583baaa | 829 | form = WidgetToForm(w); |
830 | MoiraFormComplete(NULL, form); | |
831 | } else { | |
832 | _XmMgrTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP); | |
833 | } | |
834 | } | |
835 | ||
836 | ||
837 | void CancelForm(w, event, argv, count) | |
838 | Widget w; | |
839 | XEvent *event; | |
840 | char **argv; | |
841 | Cardinal *count; | |
842 | { | |
843 | EntryForm *form; | |
844 | ||
845 | form = WidgetToForm(w); | |
846 | if (form) | |
847 | XtUnmanageChild(form->formpointer); | |
848 | } | |
849 | ||
850 | ||
851 | void ExecuteForm(w, event, argv, count) | |
852 | Widget w; | |
853 | XEvent *event; | |
854 | char **argv; | |
855 | Cardinal *count; | |
856 | { | |
857 | EntryForm *form; | |
858 | ||
859 | form = WidgetToForm(w); | |
41a6b53e | 860 | if (form) { |
861 | MoiraFocusOut(w, event, argv, count); | |
862 | MoiraFormComplete(NULL, form); | |
863 | } | |
3583baaa | 864 | } |
865 | ||
866 | ||
867 | void DoHelp(w, event, argv, count) | |
868 | Widget w; | |
869 | XEvent *event; | |
870 | char **argv; | |
871 | Cardinal *count; | |
872 | { | |
873 | EntryForm *form; | |
874 | ||
875 | form = WidgetToForm(w); | |
876 | if (form) | |
877 | help(form->formname); | |
878 | } | |
879 | ||
880 | ||
881 | extern struct hash *create_hash(); | |
882 | static struct hash *WFmap = NULL; | |
883 | ||
884 | MapWidgetToForm(w, f) | |
885 | Widget *w; | |
886 | EntryForm *f; | |
887 | { | |
888 | if (WFmap == NULL) { | |
889 | WFmap = create_hash(101); | |
890 | } | |
891 | hash_store(WFmap, w, f); | |
892 | } | |
893 | ||
894 | EntryForm *WidgetToForm(w) | |
895 | Widget *w; | |
896 | { | |
897 | return((EntryForm *) hash_lookup(WFmap, w)); | |
898 | } | |
b80b4770 | 899 | |
900 | ||
901 | /* Routines to deal with children of composite widgets */ | |
902 | ||
903 | Widget NthChild(w, n) | |
904 | CompositeRec *w; | |
905 | int n; | |
906 | { | |
907 | return(w->composite.children[n]); | |
908 | } | |
909 | ||
910 | int NumChildren(w) | |
911 | CompositeRec *w; | |
912 | { | |
913 | return(w->composite.num_children); | |
914 | } |