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