]> andersk Git - moira.git/blob - clients/mmoira/formup.c
Initial revision
[moira.git] / clients / mmoira / formup.c
1 #include        <stdio.h>
2 #include        <X11/StringDefs.h>
3 #include        <X11/IntrinsicP.h>
4 #include        <X11/Shell.h>
5 #include        <X11/Core.h>
6 #include        <X11/CoreP.h>
7 #include        <Xm/Xm.h>
8 #include        <Xm/BulletinB.h>
9 #include        <Xm/Label.h>
10 #include        <Xm/Text.h>
11 #include        <Xm/PushB.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>
18 #include        "mmoira.h"
19
20 #define HPADDING                8
21 #define WPADDING                20
22 #define MAX(a,b)        ((a > b) ? a : b)
23
24 extern Widget toplevel;
25
26 void    map_menu_widget();
27 void    manage_widget();
28 Widget  CreateForm();
29 Widget  CreateMenu();
30 Widget  BuildMenuTree();
31 int     button_callback();
32 int     radio_callback();
33 void    menu_callback();
34 void    post_menu_handler();
35
36
37 /*
38 ** Read the specification and put up a menu to match...
39 **
40 ** Something in here is making a bad button grab...It either gets the
41 ** error, 
42 **        "BadAccess (attempt to access private resource denied)
43 **         Major opcode of failed request:  28 (X_GrabButton)
44 **
45 ** or puts up the menu and permanently grabs the pointer!
46 **
47 ** All Motif pulldown menus are replaced with homebrews until I get an
48 ** updated widget set to try out.
49 */
50
51 Widget
52 CreateMenu(parent, spec, orientation)
53 Widget          parent;
54 MenuItem        **spec;
55 int             orientation;
56 {
57         Widget          menuparent;
58         MenuItem        *curmenuitem;
59         Widget          childbutton, childmenu;
60         Arg             wargs[10];
61         int             n;
62         XmString        label;          /* !@#$%^ compound string required */
63         Widget          shellparent;
64
65         label = XmStringCreate( "Complete junk", XmSTRING_DEFAULT_CHARSET);
66
67         n = 0;
68
69 /* MOTIF menus are broken.
70         XtSetArg(wargs[n], XmNlabelString, label);      n++;
71         menuparent = XmCreatePopupMenu(parent, "randommenu", wargs, n);
72 */
73
74         XtSetArg(wargs[n], XtNmappedWhenManaged, False);        n++;
75         shellparent = XtCreateApplicationShell( "shellparent", 
76                                                 transientShellWidgetClass,
77                                                 wargs, n);
78
79         n = 0;
80         if (orientation)
81                 XtSetArg(wargs[n], XtNorientation, orientation);        n++;
82         menuparent = XtCreateManagedWidget (    "row", 
83                                         xmRowColumnWidgetClass,
84                                         shellparent, wargs, n);
85                                                 
86
87 /*
88         XtAddEventHandler (     parent, ButtonPressMask, FALSE,
89                                 post_menu_handler, menuparent);
90 */
91         for (   curmenuitem = (*spec);
92                 curmenuitem;
93                 spec++, curmenuitem = (*spec)) {
94
95 #ifdef  DEBUG
96                 printf ("Making entry:  %s\n", curmenuitem->label);
97 #endif
98                 label = XmStringCreate( curmenuitem->label,
99                                         XmSTRING_DEFAULT_CHARSET);
100                 if (curmenuitem->submenu) {
101                         label = XmStringConcat(label,
102                                         XmStringCreate( "...",
103                                         XmSTRING_DEFAULT_CHARSET));
104                 }
105                 n = 0;
106                 XtSetArg(wargs[n], XmNlabelString, label);      n++;
107
108                 childbutton = XtCreateManagedWidget(    "child",
109                                 xmPushButtonGadgetClass,
110                                 menuparent, wargs, n);
111
112                 if (curmenuitem->submenu) {
113 #ifdef  DEBUG
114                         printf ("It has a submenu, which I'm recursing on...\n");
115 #endif
116 /* MOTIF menus don't work...
117                         childmenu = XmCreatePulldownMenu(menuparent,
118                                         curmenuitem->label,
119                                         NULL, 0);
120
121                         n = 0;
122                         XtSetArg(wargs[n], XmNsubMenuId, childmenu);    n++;
123
124                         childbutton = XtCreateManagedWidget(    "child",
125                                         xmCascadeButtonWidgetClass,
126                                         menuparent, wargs, n);
127 */
128
129                         childmenu = CreateMenu( childbutton, 
130                                                 curmenuitem->submenu,
131                                                 XmVERTICAL);
132                         XtAddCallback(  childbutton, XmNactivateCallback,
133                                         map_menu_widget, childmenu);
134
135                 }
136
137                 else {
138                         XtAddCallback(  childbutton, 
139                                         XmNactivateCallback, 
140                                         menu_callback, curmenuitem);
141                 }
142         }
143         XtRealizeWidget(shellparent);
144
145         return (shellparent);
146 }
147
148 /*      We don't need this, since I'm using callbacks rather than
149 **      event handlers.
150
151 void
152 post_menu_handler(w, menu, event)
153 Widget  w;
154 Widget  menu;
155 XEvent  *event;
156 {
157         Arg     wargs[10];
158         int     n;
159         Widget  button;
160
161         n = 0;
162         XtSetArg(wargs[n], XmNwhichButton, &button);      n++;
163         XtGetValues(menu, wargs, n);
164
165         if ((Widget) (event->xbutton.button) == button) {
166                 XmMenuPosition (menu, event);
167                 XtManageChild(menu);
168         }
169
170         else {
171                 printf ("Ignoring hit from 'wrong' button\n");
172         }
173 }
174 */
175
176
177 DisplayForm(spec)
178 EntryForm       *spec;
179 {
180         Widget  w;
181
182         w = CreateForm(toplevel, spec);
183         XtManageChild(w);
184 }
185
186
187 /*
188 ** Read the specification and put up a form to match...
189 */
190
191 Widget
192 CreateForm(parent, spec)
193 Widget          parent;
194 EntryForm       *spec;
195 {
196         XmBulletinBoardWidget   bb;
197         Arg             wargs[10];
198         int             i, n;
199         XmString        label;          /* compound string required */
200         Dimension       height_so_far = 0, width_so_far = 0;
201         Dimension       height, width;
202         Widget          titleW, instructionW;
203         Position        x, y;
204         Widget          shellparent;
205
206 /*
207         n = 0;
208         XtSetArg(wargs[n], XtNmappedWhenManaged, False);        n++;
209         shellparent = XtCreateApplicationShell( "shellparent", 
210                                                 topLevelShellWidgetClass,
211                                                 wargs, n);
212 */
213
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); \
218
219 #define STORESIZE       if (width > width_so_far) width_so_far = width;\
220                         height_so_far += height + HPADDING;
221
222
223         n = 0;
224         XtSetArg(wargs[n], XmNautoUnmanage, FALSE);             n++;
225         bb = (XmBulletinBoardWidget)
226                 XmCreateBulletinBoardDialog(parent, "board", wargs, n);
227
228         label = XmStringCreate(spec->formname, XmSTRING_DEFAULT_CHARSET);
229         n = 0;
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",
234                                 xmLabelWidgetClass,
235                                 bb, wargs, n);
236         GETSIZE(titleW);
237         STORESIZE;
238
239         label = XmStringCreate(spec->instructions, XmSTRING_DEFAULT_CHARSET);
240         n = 0;
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",
245                                 xmLabelWidgetClass,
246                                 bb, wargs, n);
247         GETSIZE(instructionW);
248         STORESIZE;
249
250         height = height_so_far;
251         width = width_so_far;
252         MakeInputLines((Widget) bb, &height, &width, spec->inputlines);
253         STORESIZE;
254
255         height = height_so_far;
256         width = width_so_far;
257         MakeButtons((Widget) bb, &height, &width, spec->buttons, (char *)spec);
258         STORESIZE;
259
260 /*
261 ** Center the title of the form
262 */
263         n = 0;
264         XtSetArg(wargs[n], XtNwidth, &width);                   n++;
265         XtGetValues (titleW, wargs, n);
266
267         x = (width_so_far - width) / 2;
268
269         n = 0;
270         XtSetArg(wargs[n], XtNx, x);                            n++;
271         XtSetValues (titleW, wargs, n);
272
273         spec->formpointer = (Widget) bb;
274
275         return((Widget) bb);
276 }
277
278 /*
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.
281 **
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.
286 */
287
288 MakeInputLines(parent, pheight, pwidth, inputlines)
289 Widget          parent;
290 Dimension       *pheight;
291 Dimension       *pwidth;
292 UserPrompt      **inputlines;
293 {
294         UserPrompt      *current;
295         XmString        label;          /* compound string required */
296         Arg             wargs[10];
297         int             i, n;
298         Widget          child;
299         Dimension       width, height, maxleftwidth = 0, maxrightwidth = 0;
300         Dimension       localy, leftheight = 0, rightheight = 0;
301         UserPrompt      **myinputlines = inputlines;
302         int             foo = 30;
303         Widget          children[20];
304
305         for (   current = (*myinputlines), localy = 0,  i = 0;
306                 current; 
307                 myinputlines++, current = (*myinputlines), i++) {
308
309
310 #ifdef  DEBUG
311                 printf ("Making entry %d: %s of type %d\n", 
312                                 i, current->prompt, current->type);
313 #endif
314 /*
315 ** First, make the prompt
316 */
317                 label = XmStringCreate( current->prompt, 
318                                         XmSTRING_DEFAULT_CHARSET);
319                 n = 0;
320                 XtSetArg(wargs[n], XmNlabelString, label);      n++;
321                 XtSetArg(wargs[n], XtNy, localy + *pheight);    n++;
322                 child = XtCreateManagedWidget(  "prompt",
323                                 xmLabelWidgetClass,
324                                 parent, wargs, n);
325
326                 GETSIZE(child);
327                 leftheight = height;
328                 if (width > maxleftwidth)
329                         maxleftwidth = width;
330
331 /*
332 ** Second, make the input widget
333 */
334                 n = 0;
335                 XtSetArg(wargs[n], XtNy, localy + *pheight);    n++;
336                 XtSetArg(wargs[n], XtNsensitive, 
337                         !(current->insensitive));               n++;
338                 switch (current->type) {
339                 case FT_STRING:
340                         children[i] = XtCreateManagedWidget(    "child",
341                                                 xmTextWidgetClass,
342                                                 parent, wargs, n);
343                         if (current->returnvalue.stringvalue) {
344                                 XmTextSetString (children[i], current->returnvalue.stringvalue);
345                         }
346                         GETSIZE (children[i]);
347                         rightheight = height;
348                         if (width > maxrightwidth)
349                                 maxrightwidth = width;
350                         break;
351
352                 case FT_BOOLEAN:
353                         XtSetArg(wargs[n], XmNset, current->returnvalue.booleanvalue);  n++;
354 /*
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!
358 */
359                         label = XmStringCreate( " ", XmSTRING_DEFAULT_CHARSET);
360                         XtSetArg(wargs[n], XmNlabelString, label);      n++;
361
362                         children[i] = XtCreateManagedWidget(    "ignore this",
363                                                 xmToggleButtonWidgetClass,
364                                                 parent, wargs, n);
365
366                         XtAddCallback(  children[i], XmNvalueChangedCallback,
367                                 radio_callback, NULL);
368
369                         GETSIZE (children[i]);
370                         rightheight = height;
371                         if (width > maxrightwidth)
372                                 maxrightwidth = width;
373                         break;
374
375                 case FT_KEYWORD:
376                         children[i] = XmCreateRadioBox(parent, "radio", wargs, n);
377                         XtManageChild(children[i]);     
378                         AddRadioButtons(        children[i], 
379                                                 current,
380                                                 &rightheight);
381                         GETSIZE (children[i]);
382                         if (width > maxrightwidth)
383                                 maxrightwidth = width;
384                         break;
385
386                 default:
387                         printf ("Sorry, don't recognize that type\n");
388                         break;
389                 }
390
391                 localy += MAX(rightheight, leftheight) + HPADDING;
392         }
393
394 /*
395 ** Now slide the input widgets right as far as the widest prompt.
396 */
397         n = 0;
398         XtSetArg(wargs[n], XtNx, maxleftwidth + WPADDING);      n++;
399         for (; i; i--)
400                 XtSetValues (children[i - 1], wargs, n);
401
402         *pheight = localy - HPADDING;
403         *pwidth = maxleftwidth + maxrightwidth + WPADDING;
404 }
405
406 /*
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!
410 */
411
412 AddRadioButtons(parent, prompt, pheight)
413 Widget          parent;
414 UserPrompt      *prompt;
415 Dimension       *pheight;
416 {
417         Widget  child;
418         char    *current;
419         Arg     wargs[10];
420         int     i, n;
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;
426
427         if (!keywords) {
428                 fprintf (stderr, "Warning:  No list of keywords for widget\n");
429                 return;
430         }
431         for (current=(*keywords); current; keywords++, current=(*keywords)) {
432                 n = 0;
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++;
437                 }
438                 else {
439                         XtSetArg(wargs[n], XmNset, False);      n++;
440                 }
441                 child = XtCreateManagedWidget(  current,
442                                                 xmToggleButtonGadgetClass,
443                                                 parent, wargs, n);
444
445                 XtAddCallback(  child, XmNvalueChangedCallback,
446                                 radio_callback, prompt);
447
448                 GETSIZE (child);
449                 height_so_far += height;
450         }
451 /*
452         GETSIZE (parent);
453         printf ("height of radio parent was %d\n", height);
454         n = 0;
455         XtSetArg(wargs[n], XtNheight, height_so_far);   n++;
456         XtSetValues (parent, wargs, n);
457         GETSIZE (parent);
458         printf ("height of radio parent is now %d\n", height);
459 */
460         *pheight = height_so_far;
461 }
462
463 MakeButtons(parent, pheight, pwidth, buttons, data)
464 Widget          parent;
465 Dimension       *pheight;
466 Dimension       *pwidth;
467 BottomButton    **buttons;
468 caddr_t         data;
469 {
470         BottomButton    *current;
471         XmString        label;          /* compound string required */
472         Arg             wargs[10];
473         int             i, n;
474         Dimension       newwidth, width = 25;
475         Widget          newbutton;
476
477         n = 0;
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,
483                                 parent, wargs, n);
484         *pheight += HPADDING;
485
486         for (   current=(*buttons); 
487                 current; 
488                 buttons++, current=(*buttons)) {
489
490 #ifdef  DEBUG
491                 printf ("Making a button labeled %s\n", current->label);
492 #endif
493                 label = XmStringCreate( current->label, 
494                                         XmSTRING_DEFAULT_CHARSET);
495                 n = 0;
496                 XtSetArg(wargs[n], XtNy, (*pheight));                   n++;
497                 XtSetArg(wargs[n], XtNx, width);                        n++;
498                 XtSetArg(wargs[n], XmNlabelString, label);              n++;
499
500                 newbutton = XtCreateManagedWidget(      current->label,
501                                                 xmPushButtonWidgetClass,
502                                                 parent, wargs, n);
503
504                 XtAddCallback(  newbutton, XmNactivateCallback,
505                                 current->returnfunction, data);
506                 n = 0;
507                 XtSetArg(wargs[n], XtNwidth, &newwidth);                n++;
508                 XtGetValues (newbutton, wargs, n);
509
510                 width += (newwidth + WPADDING);
511         }
512
513         (*pheight) += 100;
514 }
515
516 void
517 map_menu_widget(w, widget, call_data)
518 Widget  w, widget;
519 XmAnyCallbackStruct     *call_data;
520 {
521         Arg             wargs[10];
522         int             n;
523         Position        x, y;
524         Widget          foo;
525
526         
527         for (   x = 0, y = 0, foo = w->core.parent;
528                 foo;
529                 foo = foo->core.parent) {
530
531                 x += foo->core.x;
532                 y += foo->core.y;
533         }
534
535 /*
536         if (w->core.parent)
537                 x += w->core.parent->core.width;
538 */
539         x += w->core.width;
540         y += w->core.y;
541
542         n = 0;
543         XtSetArg(wargs[n], XtNx, x);            n++;
544         XtSetArg(wargs[n], XtNy, y);            n++;
545         XtSetValues(widget, wargs, n);
546
547         XtMapWidget(widget);    
548 }
549
550 void
551 manage_widget(w, widget, call_data)
552 Widget  w, widget;
553 XmAnyCallbackStruct     *call_data;
554 {
555         XtManageChild(widget);  
556 }
557
558 int
559 button_callback(w, client_data, call_data)
560 Widget  w;
561 EntryForm       *client_data;
562 XmAnyCallbackStruct     *call_data;
563 {
564         XtUnmanageChild(client_data->formpointer);
565 }
566
567 int
568 radio_callback(w, client_data, call_data)
569 Widget  w;
570 XmAnyCallbackStruct     *client_data;
571 XmAnyCallbackStruct     *call_data;
572 {
573         Arg             wargs[10];
574         int             i, n;
575         XmString        label;          /* !@#$ compound string required! */
576         char            *text_value;
577
578         UserPrompt      *prompt = (UserPrompt *) client_data;
579
580         printf ("radio_callback: button %x, data %x\n", w, client_data);
581
582 /*
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.
587
588         n = 0;
589         XtSetArg(wargs[n], XmNlabelString, label);      n++;
590         XtGetValues (w, wargs, n);
591
592        XmStringGetLtoR (label,
593                         XmSTRING_DEFAULT_CHARSET, &text_value);
594 */
595
596
597 /*
598 ** Unfortunately, Xt caches w->core.name into something besides a char*,
599 ** so I can't use it.  And XtName is, somehow, unavailable.
600
601         if (!prompt) {
602                 printf ("Oops!  radio_callback called from '%s' with no data\n",
603                                 w->core.name);
604                 return(0);
605         }
606
607         printf ("Replacing old value of selection, '%s', with '%s'\n",
608                         prompt->returnvalue.stringvalue,
609                         w->core.name);
610
611         strcpy(prompt->returnvalue.stringvalue, w->core.name);
612 */
613
614 }
615
616 void
617 menu_callback(w, client_data, call_data)
618 Widget  w;
619 XmAnyCallbackStruct     *client_data;
620 XmAnyCallbackStruct     *call_data;
621 {
622         MenuItem        *itemhit = (MenuItem *) client_data;
623
624 #ifdef DEBUG
625         printf  ("menu_callback: item '%s', op %d and string '%s'\n", 
626                         itemhit->label, 
627                         itemhit->operation, 
628                         itemhit->form);
629 #endif
630         MoiraMenuRequest(itemhit);
631 /*
632 ** Unmap the shell of this button.  (UGLY HACK until Motif menus work)
633 */
634
635         XtUnmapWidget(XtParent(XtParent(w)));
636 }
This page took 0.096244 seconds and 5 git commands to generate.