2 #include <X11/StringDefs.h>
3 #include <X11/IntrinsicP.h>
8 #include <Xm/BulletinB.h>
12 #include <Xm/PushBG.h>
13 #include <Xm/CascadeB.h>
14 #include <Xm/ToggleB.h>
15 #include <Xm/ToggleBG.h>
16 #include <Xm/RowColumn.h>
17 #include <Xm/Separator.h>
22 #define MAX(a,b) ((a > b) ? a : b)
24 extern Widget toplevel;
26 void map_menu_widget();
30 Widget BuildMenuTree();
31 int button_callback();
34 void post_menu_handler();
38 ** Read the specification and put up a menu to match...
40 ** Something in here is making a bad button grab...It either gets the
42 ** "BadAccess (attempt to access private resource denied)
43 ** Major opcode of failed request: 28 (X_GrabButton)
45 ** or puts up the menu and permanently grabs the pointer!
47 ** All Motif pulldown menus are replaced with homebrews until I get an
48 ** updated widget set to try out.
52 CreateMenu(parent, spec, orientation)
58 MenuItem *curmenuitem;
59 Widget childbutton, childmenu;
62 XmString label; /* !@#$%^ compound string required */
65 label = XmStringCreate( "Complete junk", XmSTRING_DEFAULT_CHARSET);
69 /* MOTIF menus are broken.
70 XtSetArg(wargs[n], XmNlabelString, label); n++;
71 menuparent = XmCreatePopupMenu(parent, "randommenu", wargs, n);
74 XtSetArg(wargs[n], XtNmappedWhenManaged, False); n++;
75 shellparent = XtCreateApplicationShell( "shellparent",
76 transientShellWidgetClass,
81 XtSetArg(wargs[n], XtNorientation, orientation); n++;
82 menuparent = XtCreateManagedWidget ( "row",
83 xmRowColumnWidgetClass,
84 shellparent, wargs, n);
88 XtAddEventHandler ( parent, ButtonPressMask, FALSE,
89 post_menu_handler, menuparent);
91 for ( curmenuitem = (*spec);
93 spec++, curmenuitem = (*spec)) {
96 printf ("Making entry: %s\n", curmenuitem->label);
98 label = XmStringCreate( curmenuitem->label,
99 XmSTRING_DEFAULT_CHARSET);
100 if (curmenuitem->submenu) {
101 label = XmStringConcat(label,
102 XmStringCreate( "...",
103 XmSTRING_DEFAULT_CHARSET));
106 XtSetArg(wargs[n], XmNlabelString, label); n++;
108 childbutton = XtCreateManagedWidget( "child",
109 xmPushButtonGadgetClass,
110 menuparent, wargs, n);
112 if (curmenuitem->submenu) {
114 printf ("It has a submenu, which I'm recursing on...\n");
116 /* MOTIF menus don't work...
117 childmenu = XmCreatePulldownMenu(menuparent,
122 XtSetArg(wargs[n], XmNsubMenuId, childmenu); n++;
124 childbutton = XtCreateManagedWidget( "child",
125 xmCascadeButtonWidgetClass,
126 menuparent, wargs, n);
129 childmenu = CreateMenu( childbutton,
130 curmenuitem->submenu,
132 XtAddCallback( childbutton, XmNactivateCallback,
133 map_menu_widget, childmenu);
138 XtAddCallback( childbutton,
140 menu_callback, curmenuitem);
143 XtRealizeWidget(shellparent);
145 return (shellparent);
148 /* We don't need this, since I'm using callbacks rather than
152 post_menu_handler(w, menu, event)
162 XtSetArg(wargs[n], XmNwhichButton, &button); n++;
163 XtGetValues(menu, wargs, n);
165 if ((Widget) (event->xbutton.button) == button) {
166 XmMenuPosition (menu, event);
171 printf ("Ignoring hit from 'wrong' button\n");
182 w = CreateForm(toplevel, spec);
188 ** Read the specification and put up a form to match...
192 CreateForm(parent, spec)
196 XmBulletinBoardWidget bb;
199 XmString label; /* compound string required */
200 Dimension height_so_far = 0, width_so_far = 0;
201 Dimension height, width;
202 Widget titleW, instructionW;
208 XtSetArg(wargs[n], XtNmappedWhenManaged, False); n++;
209 shellparent = XtCreateApplicationShell( "shellparent",
210 topLevelShellWidgetClass,
214 #define GETSIZE(foo) n = 0; \
215 XtSetArg(wargs[n], XtNwidth, &width); n++; \
216 XtSetArg(wargs[n], XtNheight, &height); n++; \
217 XtGetValues (foo, wargs, n); \
219 #define STORESIZE if (width > width_so_far) width_so_far = width;\
220 height_so_far += height + HPADDING;
224 XtSetArg(wargs[n], XmNautoUnmanage, FALSE); n++;
225 bb = (XmBulletinBoardWidget)
226 XmCreateBulletinBoardDialog(parent, "board", wargs, n);
228 label = XmStringCreate(spec->formname, XmSTRING_DEFAULT_CHARSET);
230 XtSetArg(wargs[n], XmNlabelString, label); n++;
231 XtSetArg(wargs[n], XtNx, 0); n++;
232 XtSetArg(wargs[n], XtNy, 0); n++;
233 titleW = XtCreateManagedWidget( "title",
239 label = XmStringCreate(spec->instructions, XmSTRING_DEFAULT_CHARSET);
241 XtSetArg(wargs[n], XmNlabelString, label); n++;
242 XtSetArg(wargs[n], XtNx, 0); n++;
243 XtSetArg(wargs[n], XtNy, height_so_far); n++;
244 instructionW = XtCreateManagedWidget( "title",
247 GETSIZE(instructionW);
250 height = height_so_far;
251 width = width_so_far;
252 MakeInputLines((Widget) bb, &height, &width, spec->inputlines);
255 height = height_so_far;
256 width = width_so_far;
257 MakeButtons((Widget) bb, &height, &width, spec->buttons, (char *)spec);
261 ** Center the title of the form
264 XtSetArg(wargs[n], XtNwidth, &width); n++;
265 XtGetValues (titleW, wargs, n);
267 x = (width_so_far - width) / 2;
270 XtSetArg(wargs[n], XtNx, x); n++;
271 XtSetValues (titleW, wargs, n);
273 spec->formpointer = (Widget) bb;
279 ** Pheight and pwidth start with the values-to-date of the bboard so far.
280 ** Return your height and width in them when you're done.
282 ** Positioning the widgets happens in two phases:
283 ** First, we set their y-positions as we create them.
284 ** After they're created, we go back and adjust the x-positions
285 ** according to the widest left side noted.
288 MakeInputLines(parent, pheight, pwidth, inputlines)
292 UserPrompt **inputlines;
295 XmString label; /* compound string required */
299 Dimension width, height, maxleftwidth = 0, maxrightwidth = 0;
300 Dimension localy, leftheight = 0, rightheight = 0;
301 UserPrompt **myinputlines = inputlines;
305 for ( current = (*myinputlines), localy = 0, i = 0;
307 myinputlines++, current = (*myinputlines), i++) {
311 printf ("Making entry %d: %s of type %d\n",
312 i, current->prompt, current->type);
315 ** First, make the prompt
317 label = XmStringCreate( current->prompt,
318 XmSTRING_DEFAULT_CHARSET);
320 XtSetArg(wargs[n], XmNlabelString, label); n++;
321 XtSetArg(wargs[n], XtNy, localy + *pheight); n++;
322 child = XtCreateManagedWidget( "prompt",
328 if (width > maxleftwidth)
329 maxleftwidth = width;
332 ** Second, make the input widget
335 XtSetArg(wargs[n], XtNy, localy + *pheight); n++;
336 XtSetArg(wargs[n], XtNsensitive,
337 !(current->insensitive)); n++;
338 switch (current->type) {
340 children[i] = XtCreateManagedWidget( "child",
343 if (current->returnvalue.stringvalue) {
344 XmTextSetString (children[i], current->returnvalue.stringvalue);
346 GETSIZE (children[i]);
347 rightheight = height;
348 if (width > maxrightwidth)
349 maxrightwidth = width;
353 XtSetArg(wargs[n], XmNset, current->returnvalue.booleanvalue); n++;
355 ** EEEuch! Not only to I have to use a blank (not NULL!) string to
356 ** override the ToggleButton's insistance on labelling itself, it has
357 ** to be a _compound_ blank string!
359 label = XmStringCreate( " ", XmSTRING_DEFAULT_CHARSET);
360 XtSetArg(wargs[n], XmNlabelString, label); n++;
362 children[i] = XtCreateManagedWidget( "ignore this",
363 xmToggleButtonWidgetClass,
366 XtAddCallback( children[i], XmNvalueChangedCallback,
367 radio_callback, NULL);
369 GETSIZE (children[i]);
370 rightheight = height;
371 if (width > maxrightwidth)
372 maxrightwidth = width;
376 children[i] = XmCreateRadioBox(parent, "radio", wargs, n);
377 XtManageChild(children[i]);
378 AddRadioButtons( children[i],
381 GETSIZE (children[i]);
382 if (width > maxrightwidth)
383 maxrightwidth = width;
387 printf ("Sorry, don't recognize that type\n");
391 localy += MAX(rightheight, leftheight) + HPADDING;
395 ** Now slide the input widgets right as far as the widest prompt.
398 XtSetArg(wargs[n], XtNx, maxleftwidth + WPADDING); n++;
400 XtSetValues (children[i - 1], wargs, n);
402 *pheight = localy - HPADDING;
403 *pwidth = maxleftwidth + maxrightwidth + WPADDING;
407 ** All the junk about keeping track of the sum of the children's heights
408 ** is because the !#$% RowColumn widget doesn't sum them for us, NOR
409 ** does it accept SetValues on its XtNHeight!
412 AddRadioButtons(parent, prompt, pheight)
421 XmString label; /* compound string required */
422 Dimension height, width;
423 Dimension height_so_far = 0;
424 char **keywords = prompt->keywords;
425 char *defvalue = prompt->returnvalue.stringvalue;
428 fprintf (stderr, "Warning: No list of keywords for widget\n");
431 for (current=(*keywords); current; keywords++, current=(*keywords)) {
433 label = XmStringCreate(current, XmSTRING_DEFAULT_CHARSET);
434 XtSetArg(wargs[n], XmNlabelString, label); n++;
435 if (!strcmp (current, defvalue)) {
436 XtSetArg(wargs[n], XmNset, True); n++;
439 XtSetArg(wargs[n], XmNset, False); n++;
441 child = XtCreateManagedWidget( current,
442 xmToggleButtonGadgetClass,
445 XtAddCallback( child, XmNvalueChangedCallback,
446 radio_callback, prompt);
449 height_so_far += height;
453 printf ("height of radio parent was %d\n", height);
455 XtSetArg(wargs[n], XtNheight, height_so_far); n++;
456 XtSetValues (parent, wargs, n);
458 printf ("height of radio parent is now %d\n", height);
460 *pheight = height_so_far;
463 MakeButtons(parent, pheight, pwidth, buttons, data)
467 BottomButton **buttons;
470 BottomButton *current;
471 XmString label; /* compound string required */
474 Dimension newwidth, width = 25;
478 XtSetArg(wargs[n], XtNy, *pheight); n++;
479 XtSetArg(wargs[n], XtNx, 0); n++;
480 XtSetArg(wargs[n], XtNwidth, *pwidth); n++;
481 XtCreateManagedWidget( "separator",
482 xmSeparatorWidgetClass,
484 *pheight += HPADDING;
486 for ( current=(*buttons);
488 buttons++, current=(*buttons)) {
491 printf ("Making a button labeled %s\n", current->label);
493 label = XmStringCreate( current->label,
494 XmSTRING_DEFAULT_CHARSET);
496 XtSetArg(wargs[n], XtNy, (*pheight)); n++;
497 XtSetArg(wargs[n], XtNx, width); n++;
498 XtSetArg(wargs[n], XmNlabelString, label); n++;
500 newbutton = XtCreateManagedWidget( current->label,
501 xmPushButtonWidgetClass,
504 XtAddCallback( newbutton, XmNactivateCallback,
505 current->returnfunction, data);
507 XtSetArg(wargs[n], XtNwidth, &newwidth); n++;
508 XtGetValues (newbutton, wargs, n);
510 width += (newwidth + WPADDING);
517 map_menu_widget(w, widget, call_data)
519 XmAnyCallbackStruct *call_data;
527 for ( x = 0, y = 0, foo = w->core.parent;
529 foo = foo->core.parent) {
537 x += w->core.parent->core.width;
543 XtSetArg(wargs[n], XtNx, x); n++;
544 XtSetArg(wargs[n], XtNy, y); n++;
545 XtSetValues(widget, wargs, n);
551 manage_widget(w, widget, call_data)
553 XmAnyCallbackStruct *call_data;
555 XtManageChild(widget);
559 button_callback(w, client_data, call_data)
561 EntryForm *client_data;
562 XmAnyCallbackStruct *call_data;
564 XtUnmanageChild(client_data->formpointer);
568 radio_callback(w, client_data, call_data)
570 XmAnyCallbackStruct *client_data;
571 XmAnyCallbackStruct *call_data;
575 XmString label; /* !@#$ compound string required! */
578 UserPrompt *prompt = (UserPrompt *) client_data;
580 printf ("radio_callback: button %x, data %x\n", w, client_data);
583 ** It should be _easy_ to find the value of a label, right? _WRONG!_
584 ** Have to disassemble the !@#$ compound text to get a char*, and
585 ** Motif doesn't provide any functions to do so. So I stash the label
586 ** value as the name of the widget.
589 XtSetArg(wargs[n], XmNlabelString, label); n++;
590 XtGetValues (w, wargs, n);
592 XmStringGetLtoR (label,
593 XmSTRING_DEFAULT_CHARSET, &text_value);
598 ** Unfortunately, Xt caches w->core.name into something besides a char*,
599 ** so I can't use it. And XtName is, somehow, unavailable.
602 printf ("Oops! radio_callback called from '%s' with no data\n",
607 printf ("Replacing old value of selection, '%s', with '%s'\n",
608 prompt->returnvalue.stringvalue,
611 strcpy(prompt->returnvalue.stringvalue, w->core.name);
617 menu_callback(w, client_data, call_data)
619 XmAnyCallbackStruct *client_data;
620 XmAnyCallbackStruct *call_data;
622 MenuItem *itemhit = (MenuItem *) client_data;
625 printf ("menu_callback: item '%s', op %d and string '%s'\n",
630 MoiraMenuRequest(itemhit);
632 ** Unmap the shell of this button. (UGLY HACK until Motif menus work)
635 XtUnmapWidget(XtParent(XtParent(w)));