]> andersk Git - moira.git/blame - clients/mmoira/formup.c
Initial revision
[moira.git] / clients / mmoira / formup.c
CommitLineData
7ee9b49f 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
ecb7d146 20#define PADDING 10
7ee9b49f 21#define MAX(a,b) ((a > b) ? a : b)
ecb7d146 22#define MIN(a,b) ((a < b) ? a : b)
7ee9b49f 23
24extern Widget toplevel;
25
26void map_menu_widget();
27void manage_widget();
28Widget CreateForm();
29Widget CreateMenu();
30Widget BuildMenuTree();
ecb7d146 31Widget MakeRadioField();
32void button_callback();
33void radio_callback();
34void boolean_callback();
35void string_callback();
7ee9b49f 36void menu_callback();
37void post_menu_handler();
38
39
ecb7d146 40DisplayForm(spec)
41EntryForm *spec;
42{
43 Widget w;
44
45 w = CreateForm(toplevel, spec);
46 XtManageChild(w);
47}
48
7ee9b49f 49/*
50** Read the specification and put up a menu to match...
51**
52** Something in here is making a bad button grab...It either gets the
53** error,
54** "BadAccess (attempt to access private resource denied)
55** Major opcode of failed request: 28 (X_GrabButton)
56**
57** or puts up the menu and permanently grabs the pointer!
58**
59** All Motif pulldown menus are replaced with homebrews until I get an
60** updated widget set to try out.
61*/
62
63Widget
64CreateMenu(parent, spec, orientation)
65Widget parent;
66MenuItem **spec;
67int orientation;
68{
69 Widget menuparent;
70 MenuItem *curmenuitem;
71 Widget childbutton, childmenu;
72 Arg wargs[10];
73 int n;
74 XmString label; /* !@#$%^ compound string required */
ecb7d146 75 int mark = 0;
7ee9b49f 76
77 label = XmStringCreate( "Complete junk", XmSTRING_DEFAULT_CHARSET);
78
79 n = 0;
7ee9b49f 80 XtSetArg(wargs[n], XmNlabelString, label); n++;
7ee9b49f 81
ecb7d146 82 if (orientation == XmHORIZONTAL)
83 if (mark) {
84 menuparent = XmCreateMenuBar( parent, "randommenu",
85 wargs, n);
86 XtManageChild(menuparent);
87 }
88 else
89 menuparent = XmCreatePopupMenu( parent, "randommenu",
90 wargs, n);
91 else
92 menuparent = XmCreatePulldownMenu(parent, "randommenu",
93 wargs, n);
94
95#ifdef OLDCODE
7ee9b49f 96 XtSetArg(wargs[n], XtNmappedWhenManaged, False); n++;
97 shellparent = XtCreateApplicationShell( "shellparent",
98 transientShellWidgetClass,
99 wargs, n);
100
101 n = 0;
102 if (orientation)
103 XtSetArg(wargs[n], XtNorientation, orientation); n++;
104 menuparent = XtCreateManagedWidget ( "row",
105 xmRowColumnWidgetClass,
106 shellparent, wargs, n);
107
ecb7d146 108#endif
7ee9b49f 109
7ee9b49f 110 XtAddEventHandler ( parent, ButtonPressMask, FALSE,
111 post_menu_handler, menuparent);
ecb7d146 112
7ee9b49f 113 for ( curmenuitem = (*spec);
114 curmenuitem;
115 spec++, curmenuitem = (*spec)) {
116
117#ifdef DEBUG
118 printf ("Making entry: %s\n", curmenuitem->label);
119#endif
120 label = XmStringCreate( curmenuitem->label,
121 XmSTRING_DEFAULT_CHARSET);
7ee9b49f 122 n = 0;
123 XtSetArg(wargs[n], XmNlabelString, label); n++;
124
7ee9b49f 125 if (curmenuitem->submenu) {
126#ifdef DEBUG
127 printf ("It has a submenu, which I'm recursing on...\n");
128#endif
ecb7d146 129 childmenu = CreateMenu( menuparent,
130 curmenuitem->submenu,
131 XmVERTICAL);
7ee9b49f 132 XtSetArg(wargs[n], XmNsubMenuId, childmenu); n++;
133
134 childbutton = XtCreateManagedWidget( "child",
135 xmCascadeButtonWidgetClass,
136 menuparent, wargs, n);
7ee9b49f 137
7ee9b49f 138 XtAddCallback( childbutton, XmNactivateCallback,
139 map_menu_widget, childmenu);
140
141 }
142
143 else {
ecb7d146 144 childbutton = XtCreateManagedWidget( "child",
145 xmPushButtonGadgetClass,
146 menuparent, wargs, n);
147
7ee9b49f 148 XtAddCallback( childbutton,
149 XmNactivateCallback,
150 menu_callback, curmenuitem);
151 }
152 }
ecb7d146 153 XtRealizeWidget(menuparent);
7ee9b49f 154
ecb7d146 155 return (menuparent);
7ee9b49f 156}
157
7ee9b49f 158void
159post_menu_handler(w, menu, event)
160Widget w;
161Widget menu;
162XEvent *event;
163{
164 Arg wargs[10];
165 int n;
166 Widget button;
167
168 n = 0;
169 XtSetArg(wargs[n], XmNwhichButton, &button); n++;
170 XtGetValues(menu, wargs, n);
171
172 if ((Widget) (event->xbutton.button) == button) {
173 XmMenuPosition (menu, event);
174 XtManageChild(menu);
175 }
176
177 else {
ecb7d146 178/* printf ("Ignoring hit from 'wrong' button\n"); */
7ee9b49f 179 }
180}
7ee9b49f 181
182
7ee9b49f 183
184/*
185** Read the specification and put up a form to match...
186*/
187
188Widget
189CreateForm(parent, spec)
190Widget parent;
191EntryForm *spec;
192{
ecb7d146 193 Widget bb;
7ee9b49f 194 Arg wargs[10];
ecb7d146 195 int n;
7ee9b49f 196 XmString label; /* compound string required */
197 Dimension height_so_far = 0, width_so_far = 0;
198 Dimension height, width;
199 Widget titleW, instructionW;
200 Position x, y;
201 Widget shellparent;
202
ecb7d146 203 if (spec->formpointer) {
204 printf ("Form %s already exists\n", spec->formname);
205 return(spec->formpointer);
206 }
7ee9b49f 207
208#define GETSIZE(foo) n = 0; \
209 XtSetArg(wargs[n], XtNwidth, &width); n++; \
210 XtSetArg(wargs[n], XtNheight, &height); n++; \
211 XtGetValues (foo, wargs, n); \
212
213#define STORESIZE if (width > width_so_far) width_so_far = width;\
ecb7d146 214 height_so_far += height + PADDING;
7ee9b49f 215
216
217 n = 0;
218 XtSetArg(wargs[n], XmNautoUnmanage, FALSE); n++;
ecb7d146 219 bb = XmCreateBulletinBoardDialog(parent, "board", wargs, n);
220
221/*
222 XmAddTabGroup(bb);
223*/
224
225 spec->formpointer = bb;
7ee9b49f 226
227 label = XmStringCreate(spec->formname, XmSTRING_DEFAULT_CHARSET);
228 n = 0;
229 XtSetArg(wargs[n], XmNlabelString, label); n++;
230 XtSetArg(wargs[n], XtNx, 0); n++;
231 XtSetArg(wargs[n], XtNy, 0); n++;
232 titleW = XtCreateManagedWidget( "title",
233 xmLabelWidgetClass,
234 bb, wargs, n);
235 GETSIZE(titleW);
236 STORESIZE;
237
238 label = XmStringCreate(spec->instructions, XmSTRING_DEFAULT_CHARSET);
239 n = 0;
240 XtSetArg(wargs[n], XmNlabelString, label); n++;
241 XtSetArg(wargs[n], XtNx, 0); n++;
242 XtSetArg(wargs[n], XtNy, height_so_far); n++;
243 instructionW = XtCreateManagedWidget( "title",
244 xmLabelWidgetClass,
245 bb, wargs, n);
246 GETSIZE(instructionW);
247 STORESIZE;
248
249 height = height_so_far;
250 width = width_so_far;
ecb7d146 251 MakeInputLines(bb, &height, &width, spec);
7ee9b49f 252 STORESIZE;
253
254 height = height_so_far;
255 width = width_so_far;
ecb7d146 256 MakeButtons(bb, &height, &width, spec);
7ee9b49f 257 STORESIZE;
258
259/*
260** Center the title of the form
261*/
262 n = 0;
263 XtSetArg(wargs[n], XtNwidth, &width); n++;
264 XtGetValues (titleW, wargs, n);
265
266 x = (width_so_far - width) / 2;
267
268 n = 0;
269 XtSetArg(wargs[n], XtNx, x); n++;
270 XtSetValues (titleW, wargs, n);
271
7ee9b49f 272 return((Widget) bb);
273}
274
275/*
276** Pheight and pwidth start with the values-to-date of the bboard so far.
277** Return your height and width in them when you're done.
278**
279** Positioning the widgets happens in two phases:
280** First, we set their y-positions as we create them.
281** After they're created, we go back and adjust the x-positions
282** according to the widest left side noted.
283*/
284
ecb7d146 285MakeInputLines(parent, pheight, pwidth, spec)
7ee9b49f 286Widget parent;
287Dimension *pheight;
288Dimension *pwidth;
ecb7d146 289EntryForm *spec;
7ee9b49f 290{
291 UserPrompt *current;
292 XmString label; /* compound string required */
293 Arg wargs[10];
294 int i, n;
295 Widget child;
296 Dimension width, height, maxleftwidth = 0, maxrightwidth = 0;
297 Dimension localy, leftheight = 0, rightheight = 0;
ecb7d146 298 UserPrompt **myinputlines = spec->inputlines;
7ee9b49f 299 int foo = 30;
300 Widget children[20];
301
ecb7d146 302/*
303 XmAddTabGroup(parent);
304*/
7ee9b49f 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++;
ecb7d146 336 XtSetArg(wargs[n], XmNtraversalOn, True); n++;
7ee9b49f 337 XtSetArg(wargs[n], XtNsensitive,
338 !(current->insensitive)); n++;
339 switch (current->type) {
340 case FT_STRING:
341 children[i] = XtCreateManagedWidget( "child",
342 xmTextWidgetClass,
343 parent, wargs, n);
ecb7d146 344 XtAddCallback( children[i], XmNlosingFocusCallback,
345 string_callback, current);
7ee9b49f 346 if (current->returnvalue.stringvalue) {
347 XmTextSetString (children[i], current->returnvalue.stringvalue);
348 }
349 GETSIZE (children[i]);
350 rightheight = height;
351 if (width > maxrightwidth)
352 maxrightwidth = width;
353 break;
354
355 case FT_BOOLEAN:
356 XtSetArg(wargs[n], XmNset, current->returnvalue.booleanvalue); n++;
ecb7d146 357
358 if (current->returnvalue.booleanvalue)
359 label = XmStringCreate( "(True)", XmSTRING_DEFAULT_CHARSET);
360 else
361 label = XmStringCreate( "(False)", XmSTRING_DEFAULT_CHARSET);
7ee9b49f 362 XtSetArg(wargs[n], XmNlabelString, label); n++;
363
364 children[i] = XtCreateManagedWidget( "ignore this",
365 xmToggleButtonWidgetClass,
366 parent, wargs, n);
367
368 XtAddCallback( children[i], XmNvalueChangedCallback,
ecb7d146 369 boolean_callback, current);
7ee9b49f 370
371 GETSIZE (children[i]);
372 rightheight = height;
373 if (width > maxrightwidth)
374 maxrightwidth = width;
375 break;
376
377 case FT_KEYWORD:
ecb7d146 378 children[i] =
379 MakeRadioField(parent, current, &rightheight);
380 XtManageChild(children[i]);
381 XtSetValues(children[i], wargs, n);
7ee9b49f 382 GETSIZE (children[i]);
383 if (width > maxrightwidth)
384 maxrightwidth = width;
385 break;
386
387 default:
388 printf ("Sorry, don't recognize that type\n");
389 break;
390 }
ecb7d146 391 XmAddTabGroup(children[i]);
7ee9b49f 392
ecb7d146 393 localy += MAX(rightheight, leftheight) + PADDING;
7ee9b49f 394 }
395
396/*
397** Now slide the input widgets right as far as the widest prompt.
398*/
399 n = 0;
ecb7d146 400 XtSetArg(wargs[n], XtNx, maxleftwidth + PADDING); n++;
7ee9b49f 401 for (; i; i--)
402 XtSetValues (children[i - 1], wargs, n);
403
ecb7d146 404 *pheight = localy - PADDING;
405 *pwidth = maxleftwidth + maxrightwidth + PADDING;
7ee9b49f 406}
407
408/*
409** All the junk about keeping track of the sum of the children's heights
410** is because the !#$% RowColumn widget doesn't sum them for us, NOR
ecb7d146 411** does it accept SetValues on its XtNHeight! Thanks, Motif!
7ee9b49f 412*/
413
ecb7d146 414Widget
415MakeRadioField(parent, prompt, pheight)
7ee9b49f 416Widget parent;
417UserPrompt *prompt;
418Dimension *pheight;
419{
ecb7d146 420 Widget radioparent, child;
7ee9b49f 421 char *current;
422 Arg wargs[10];
ecb7d146 423 int count, n;
424 XmString label; /* accursed compound string required */
7ee9b49f 425 Dimension height, width;
ecb7d146 426 char **keywords;
7ee9b49f 427
ecb7d146 428
429 if (!prompt->keywords) {
7ee9b49f 430 fprintf (stderr, "Warning: No list of keywords for widget\n");
ecb7d146 431 return((Widget) NULL);
7ee9b49f 432 }
ecb7d146 433 for ( count = 0, keywords = prompt->keywords;
434 *keywords;
435 keywords++, count++);
436
437/*
438** Although the XmNnumColumns resource is documented as actually
439** representing the number of _rows_ when XmNorientation is set to XmVERTICAL,
440** it doesn't. So I need to count the items myself and manually set the
441** number of columns to get a maximum of five rows. There's no XmNnumRows
442** resource. Thanks, Motif!
443*/
444
445 n = 0;
446 if (count > 5) {
447 printf ("Special case: Asking for %d columns\n",1 + count/5);
448 XtSetArg(wargs[n], XmNnumColumns, 1 + count / 5); n++;
449 XtSetArg(wargs[n], XmNorientation, XmVERTICAL); n++;
450 XtSetArg(wargs[n], XmNpacking, XmPACK_COLUMN); n++;
451 }
452
453 radioparent = XmCreateRadioBox(parent, "radio", wargs, n);
454
455 keywords = prompt->keywords;
7ee9b49f 456 for (current=(*keywords); current; keywords++, current=(*keywords)) {
457 n = 0;
458 label = XmStringCreate(current, XmSTRING_DEFAULT_CHARSET);
459 XtSetArg(wargs[n], XmNlabelString, label); n++;
ecb7d146 460 if (!strcmp (current, prompt->returnvalue.stringvalue)) {
7ee9b49f 461 XtSetArg(wargs[n], XmNset, True); n++;
462 }
463 else {
464 XtSetArg(wargs[n], XmNset, False); n++;
465 }
466 child = XtCreateManagedWidget( current,
467 xmToggleButtonGadgetClass,
ecb7d146 468 radioparent, wargs, n);
7ee9b49f 469
470 XtAddCallback( child, XmNvalueChangedCallback,
471 radio_callback, prompt);
472
7ee9b49f 473 }
474/*
ecb7d146 475** Assume all child widgets are the same height. Increase height by
476** five times this, or the actual number of children, whichever is lesser.
477*/
478
479 GETSIZE (child);
480 printf ("Reporting height of %d\n", (height * MAX(5, count)));
481 *pheight = (height * MIN(5, count));
482
483/*
7ee9b49f 484 n = 0;
485 XtSetArg(wargs[n], XtNheight, height_so_far); n++;
ecb7d146 486 XtSetValues (radioparent, wargs, n);
487 GETSIZE (radioparent);
7ee9b49f 488 printf ("height of radio parent is now %d\n", height);
ecb7d146 489
490
7ee9b49f 491 *pheight = height_so_far;
ecb7d146 492*/
493 return(radioparent);
7ee9b49f 494}
495
ecb7d146 496MakeButtons(parent, pheight, pwidth, spec)
7ee9b49f 497Widget parent;
498Dimension *pheight;
499Dimension *pwidth;
ecb7d146 500EntryForm *spec;
7ee9b49f 501{
502 BottomButton *current;
503 XmString label; /* compound string required */
504 Arg wargs[10];
505 int i, n;
506 Dimension newwidth, width = 25;
507 Widget newbutton;
ecb7d146 508 BottomButton **buttons = spec->buttons;
7ee9b49f 509
510 n = 0;
511 XtSetArg(wargs[n], XtNy, *pheight); n++;
512 XtSetArg(wargs[n], XtNx, 0); n++;
513 XtSetArg(wargs[n], XtNwidth, *pwidth); n++;
514 XtCreateManagedWidget( "separator",
515 xmSeparatorWidgetClass,
516 parent, wargs, n);
ecb7d146 517 *pheight += PADDING;
7ee9b49f 518
519 for ( current=(*buttons);
520 current;
521 buttons++, current=(*buttons)) {
522
523#ifdef DEBUG
524 printf ("Making a button labeled %s\n", current->label);
525#endif
526 label = XmStringCreate( current->label,
527 XmSTRING_DEFAULT_CHARSET);
528 n = 0;
529 XtSetArg(wargs[n], XtNy, (*pheight)); n++;
530 XtSetArg(wargs[n], XtNx, width); n++;
531 XtSetArg(wargs[n], XmNlabelString, label); n++;
532
533 newbutton = XtCreateManagedWidget( current->label,
534 xmPushButtonWidgetClass,
535 parent, wargs, n);
536
537 XtAddCallback( newbutton, XmNactivateCallback,
ecb7d146 538 current->returnfunction, spec);
7ee9b49f 539 n = 0;
540 XtSetArg(wargs[n], XtNwidth, &newwidth); n++;
541 XtGetValues (newbutton, wargs, n);
542
ecb7d146 543 width += (newwidth + PADDING);
7ee9b49f 544 }
545
546 (*pheight) += 100;
547}
548
549void
550map_menu_widget(w, widget, call_data)
551Widget w, widget;
552XmAnyCallbackStruct *call_data;
553{
554 Arg wargs[10];
555 int n;
556 Position x, y;
557 Widget foo;
558
559
560 for ( x = 0, y = 0, foo = w->core.parent;
561 foo;
562 foo = foo->core.parent) {
563
564 x += foo->core.x;
565 y += foo->core.y;
566 }
567
568/*
569 if (w->core.parent)
570 x += w->core.parent->core.width;
571*/
572 x += w->core.width;
573 y += w->core.y;
574
575 n = 0;
576 XtSetArg(wargs[n], XtNx, x); n++;
577 XtSetArg(wargs[n], XtNy, y); n++;
578 XtSetValues(widget, wargs, n);
579
580 XtMapWidget(widget);
581}
582
583void
584manage_widget(w, widget, call_data)
585Widget w, widget;
586XmAnyCallbackStruct *call_data;
587{
588 XtManageChild(widget);
589}
590
ecb7d146 591void
592button_callback(w, form, call_data)
7ee9b49f 593Widget w;
ecb7d146 594EntryForm *form;
7ee9b49f 595XmAnyCallbackStruct *call_data;
596{
ecb7d146 597 XtUnmanageChild(form->formpointer);
7ee9b49f 598}
599
ecb7d146 600void
7ee9b49f 601radio_callback(w, client_data, call_data)
602Widget w;
603XmAnyCallbackStruct *client_data;
604XmAnyCallbackStruct *call_data;
605{
606 Arg wargs[10];
ecb7d146 607 int n;
608 Boolean is_set;
7ee9b49f 609
610 UserPrompt *prompt = (UserPrompt *) client_data;
611
7ee9b49f 612 n = 0;
ecb7d146 613 XtSetArg(wargs[n], XmNset, &is_set); n++;
7ee9b49f 614 XtGetValues (w, wargs, n);
615
ecb7d146 616 if (!is_set)
617 return;
7ee9b49f 618
619/*
ecb7d146 620** Since Motif insists on using !@#$% Compound Strings as the text for
621** its label widgets, but doesn't provide a way of getting a char* back
622** from a !@#$% Compound String, I can't retrieve the label of the button
623** that was hit.
624**
625** Fortunately, I was smart enough to use the button label as the name
626** of the widget, and I can extract it via XtName(). Thanks, Motif!
627*/
7ee9b49f 628
629 printf ("Replacing old value of selection, '%s', with '%s'\n",
630 prompt->returnvalue.stringvalue,
ecb7d146 631 XtName(w));
7ee9b49f 632
ecb7d146 633 strcpy(prompt->returnvalue.stringvalue, XtName(w));
634}
635
636void
637boolean_callback(w, client_data, call_data)
638Widget w;
639XmAnyCallbackStruct *client_data;
640XmAnyCallbackStruct *call_data;
641{
642 Arg wargs[10];
643 int n;
644 Boolean is_set;
645 UserPrompt *current = (UserPrompt *)client_data;
646 XmString label;
647
648 n = 0;
649 XtSetArg(wargs[n], XmNset, &is_set); n++;
650 XtGetValues (w, wargs, n);
651
652 current->returnvalue.booleanvalue = is_set;
7ee9b49f 653
ecb7d146 654 if (is_set)
655 label = XmStringCreate( "(True)", XmSTRING_DEFAULT_CHARSET);
656 else
657 label = XmStringCreate( "(False)", XmSTRING_DEFAULT_CHARSET);
658 n = 0;
659 XtSetArg(wargs[n], XmNlabelString, label); n++;
660 XtSetValues (w, wargs, n);
661
662#if DEBUG
663 printf ("boolean_callback: button %x is %s\n",
664 w, (is_set ? "True" : "False"));
665#endif
7ee9b49f 666}
667
668void
669menu_callback(w, client_data, call_data)
670Widget w;
671XmAnyCallbackStruct *client_data;
672XmAnyCallbackStruct *call_data;
673{
674 MenuItem *itemhit = (MenuItem *) client_data;
675
ecb7d146 676/* printf ("menu_callback: item '%s', op %d and string '%s'\n",
7ee9b49f 677 itemhit->label,
678 itemhit->operation,
ecb7d146 679 itemhit->form); */
7ee9b49f 680 MoiraMenuRequest(itemhit);
ecb7d146 681}
7ee9b49f 682
ecb7d146 683void
684string_callback(w, client_data, call_data)
685Widget w;
686XmAnyCallbackStruct *client_data;
687XmAnyCallbackStruct *call_data;
688{
689 UserPrompt *current = (UserPrompt *)client_data;
690 char *newvalue;
691
692 newvalue = XmTextGetString(w);
693
694 printf ("Replacing old value of selection, '%s', with '%s'\n",
695 current->returnvalue.stringvalue,
696 newvalue);
697 strcpy(current->returnvalue.stringvalue, newvalue);
698 XtFree(newvalue);
7ee9b49f 699}
This page took 0.151469 seconds and 5 git commands to generate.