changed reading hint
[gromacs/adressmacs.git] / src / gmxlib / mgmx.c
blob221ac3f8168f7218af745b3dc2495ab04a1ad0c7
1 /*
2 * $Id$
3 *
4 * This source code is part of
5 *
6 * G R O M A C S
7 *
8 * GROningen MAchine for Chemical Simulations
9 *
10 * VERSION 2.0
12 * Copyright (c) 1991-1999
13 * BIOSON Research Institute, Dept. of Biophysical Chemistry
14 * University of Groningen, The Netherlands
16 * Please refer to:
17 * GROMACS: A message-passing parallel molecular dynamics implementation
18 * H.J.C. Berendsen, D. van der Spoel and R. van Drunen
19 * Comp. Phys. Comm. 91, 43-56 (1995)
21 * Also check out our WWW page:
22 * http://md.chem.rug.nl/~gmx
23 * or e-mail to:
24 * gromacs@chem.rug.nl
26 * And Hey:
27 * Green Red Orange Magenta Azure Cyan Skyblue
29 static char *SRCID_mgmx_c = "$Id$";
31 #include <string.h>
32 #include <ctype.h>
34 #include <Xm/Xm.h>
35 #include <Xm/ScrolledW.h>
36 #include <Xm/ScrollBar.h>
37 #include <Xm/PushB.h>
38 #include <Xm/PushBP.h>
39 #include <Xm/ToggleB.h>
40 #include <Xm/ArrowB.h>
41 #include <Xm/CascadeB.h>
42 #include <Xm/Separator.h>
43 #include <Xm/DrawnB.h>
44 #include <Xm/DialogS.h>
45 #include <Xm/Scale.h>
46 #include <Xm/Frame.h>
47 #include <Xm/FileSB.h>
48 #include <Xm/Form.h>
49 #include <Xm/RowColumn.h>
50 #include <Xm/Label.h>
51 #include <Xm/TextF.h>
52 #include <Xm/Text.h>
53 #include <Xm/List.h>
54 #include <Xm/DrawingA.h>
55 #include <Xm/MenuShell.h>
56 #include <Xm/MessageB.h>
57 #include <X11/Shell.h>
58 #include <X11/StringDefs.h>
60 #include "typedefs.h"
61 #include "copyrite.h"
62 #include "smalloc.h"
63 #include "string2.h"
64 #include "statutil.h"
65 #include "wman.h"
66 #include "macros.h"
67 #include "widget.h"
68 #include "names.h"
70 typedef struct {
71 char *label;
72 char *desc;
73 void (*cbfn)();
74 } t_button;
76 /* global variables */
77 #define NARGS 20
78 static Arg args[NARGS];
79 static Widget FdlgCaller;
80 static int helpw=-1,aboutw=-1,descw=-1,fdlgw=-1,gmxDialog;
81 static int *pa_index,*pa_set_index,*fnm_index;
82 static bool bFdlgUp=FALSE,bDone=FALSE,bDescSet=FALSE;
83 extern XmString empty_str;
84 static XmString desc_str;
86 #define GMXDLG "gmxdlg"
87 #define GMXTOGGLE "gmxtoggle"
88 #define GMXEDIT "gmxedit"
89 #define GMXBUTTON "gmxbutton"
90 #define GMXPD "gmxpd"
91 #define GMXDESC "gmxdesc"
92 #define GMXSEP "gmxsep"
93 #define GMXHELP "gmxhelp"
94 #define GMXSCROLL "gmxscroll"
95 #define GMXFILE "gmxfile"
97 /* Height handling routines */
98 static windex TopW=0,NewTopW=0;
99 static void set_top_windex(windex t)
101 NewTopW = t;
104 static windex top_windex(void)
106 if (TopW == 0)
107 fatal_error(0,"No top widget");
108 return TopW;
111 static void new_windex_row(void)
113 if ((NewTopW == 0) && (TopW != 0)) {
114 if (debug)
115 fprintf(debug,"Empty windex row!\n");
117 else {
118 TopW = NewTopW;
119 NewTopW = 0;
123 /******************************************************************
125 * C A L L B A C K R O U T I N E S
127 ******************************************************************/
129 static void cancel_callback(Widget w,caddr_t client_data,caddr_t call_data)
131 printf("Maybe next time...\n");
132 thanx(stdout);
133 exit(0);
136 static void ok_callback(Widget w,caddr_t client_data,caddr_t call_data)
138 bDone = TRUE;
141 static void help_callback(Widget w,caddr_t client_data,caddr_t call_data)
143 XtManageChild(get_widget(helpw));
146 static void help_ok_callback(Widget w,caddr_t client_data,caddr_t call_data)
148 XtUnmanageChild(get_widget(helpw));
151 static void about_callback(Widget w,caddr_t client_data,caddr_t call_data)
153 XtManageChild(get_widget(aboutw));
156 static void about_ok_callback(Widget w,caddr_t client_data,caddr_t call_data)
158 XtUnmanageChild(get_widget(aboutw));
161 static void file_callback(Widget www,caddr_t client_data,caddr_t call_data)
163 int ftp,narg;
164 Widget fdlg;
165 XmString xms;
167 if (fdlgw != -1) {
168 if (bFdlgUp)
169 fprintf(stderr,"Only one file selector box at a time!\n");
170 else {
171 fdlg = get_widget(fdlgw);
172 if ((ftp = get_widget_ftp(www)) != -1) {
173 xms = char2xms(ftp2filter(ftp));
174 narg = 0;
175 XtSetArg(args[narg],XmNdirMask,xms); narg++;
176 XtSetArg(args[narg],XmNpattern,xms); narg++;
177 XtSetArg(args[narg],XmNlistUpdated, False); narg++;
179 XtSetValues(fdlg,args,narg);
180 XmStringFree(xms);
182 XtManageChild(fdlg);
183 bFdlgUp = TRUE;
184 FdlgCaller = get_widget_other(get_windex(www),TRUE);
189 static void file_ok_callback(Widget www,int *which,
190 XmFileSelectionBoxCallbackStruct *xmf)
192 if (bFdlgUp) {
193 if ((xmf->reason == XmCR_OK) && (xmf->length > 0))
194 set_widget_dir(FdlgCaller,xmf->value);
196 XtUnmanageChild(get_widget(fdlgw));
197 bFdlgUp = FALSE;
201 static void file_cancel_callback(Widget www,int *which,
202 XmFileSelectionBoxCallbackStruct *xmf)
204 if (bFdlgUp) {
205 XtUnmanageChild(get_widget(fdlgw));
206 bFdlgUp = FALSE;
210 static void enter_callback(Widget www,int *which,caddr_t call_data)
212 int narg;
214 if (descw != -1) {
215 if (have_windex_desc(get_windex(www))) {
216 narg=0;
217 XtSetArg(args[narg],XmNlabelString,get_widget_desc(www)); narg++;
218 XtSetValues(get_widget(descw),args,narg);
219 bDescSet = TRUE;
224 static void leave_callback(Widget www,int *which,caddr_t call_data)
226 int narg;
228 if (descw != -1) {
229 if (bDescSet) {
230 narg=0;
231 XtSetArg(args[narg],XmNlabelString,desc_str); narg++;
232 XtSetValues(get_widget(descw),args,narg);
233 bDescSet = FALSE;
238 /************************************************************************
240 * S E T T I N G U P T H E D I A L O G B O X
242 ************************************************************************/
244 static void mk_desc_handlers(void)
246 Widget www;
247 int i;
249 for(i=0; (i<nwidget()); i++) {
250 if (have_windex_desc(i)) {
251 www = get_widget(i);
252 XtAddEventHandler(www,EnterWindowMask,True,
253 (XtEventHandler) enter_callback,&i);
254 XtAddEventHandler(www,LeaveWindowMask,True,
255 (XtEventHandler) leave_callback,&i);
258 empty_str = char2xms("");
261 static int mk_toggle(int parent,char *title,int top,int left,
262 bool bStatus,char *desc)
264 int narg;
266 narg = 0;
267 if (top == parent) {
268 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_FORM); narg++;
270 else {
271 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_WIDGET); narg++;
272 XtSetArg(args[narg],XmNtopWidget, get_widget(top)); narg++;
274 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_POSITION); narg++;
275 XtSetArg(args[narg],XmNleftPosition, left+1); narg++;
276 XtSetArg(args[narg],XmNrightAttachment,XmATTACH_NONE); narg++;
277 /*XtSetArg(args[narg],XmNindicatorType, XmONE_OF_MANY); narg++;*/
278 /*XtSetArg(args[narg],XmNvisibleWhenOff, False); narg++;*/
279 /*XtSetArg(args[narg],XmNselectPixmap*/
280 XtSetArg(args[narg],XmNindicatorOn, True); narg++;
281 if (bStatus) {
282 XtSetArg(args[narg],XmNset, True); narg++;
284 XtSetArg(args[narg],XmNlabelString, char2xms(title)); narg++;
286 return add_widget(XtCreateWidget(GMXTOGGLE,xmToggleButtonWidgetClass,
287 get_widget(parent),args,narg),desc);
290 static void mk_editor(int paindex,int parent,int top,int left,
291 char *label,char *initial_value,char *desc)
293 enum { nwcTOGGLE, nwcTEXT, NWC };
294 WidgetClass wc[NWC];
295 char *wlab[NWC];
296 int rleft[NWC] = { 1, 22 };
297 int rright[NWC]= { 21, 49 };
298 int ww[NWC];
299 int j,narg;
301 /* Create & Position the label */
302 wc[nwcTOGGLE] = xmToggleButtonWidgetClass;
303 wc[nwcTEXT] = xmTextFieldWidgetClass;
304 wlab[nwcTOGGLE] = GMXTOGGLE;
305 wlab[nwcTEXT] = GMXEDIT;
307 for(j=0; (j<NWC); j++) {
308 narg = 0;
309 if (top == parent) {
310 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_FORM); narg++;
312 else {
313 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_WIDGET); narg++;
314 XtSetArg(args[narg],XmNtopWidget, get_widget(top)); narg++;
316 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_POSITION); narg++;
317 XtSetArg(args[narg],XmNleftPosition, left+rleft[j]); narg++;
318 if (j == nwcTOGGLE) {
319 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_NONE); narg++;
321 else {
322 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_POSITION); narg++;
323 XtSetArg(args[narg],XmNrightPosition, left+rright[j]); narg++;
325 XtSetArg(args[narg],XmNbottomAttachment, XmATTACH_NONE); narg++;
326 if (j == nwcTEXT) {
327 XtSetArg(args[narg],XmNvalue, initial_value); narg++;
329 else {
330 XtSetArg(args[narg],XmNlabelString, char2xms(label)); narg++;
332 if (debug)
333 fprintf(debug,"There are %d args for %s\n",narg,wlab[j]);
334 ww[j] = add_widget(XtCreateWidget(wlab[j],wc[j],
335 get_widget(parent),args,narg),desc);
337 pa_set_index[paindex] = ww[nwcTOGGLE];
338 pa_index[paindex] = ww[nwcTEXT];
341 static void mk_enumerated(int parent,int top,int left,
342 int *wlabel,int *wtextf,
343 char *label,char **but,char *desc)
345 enum { nwcTOGGLE, nwcBUTTON, NWC };
346 WidgetClass wc[NWC];
347 int pd;
348 char *wlab[NWC],buf[256];
349 int rleft[NWC] = { 1, 22 };
350 int rright[NWC]= { 21, 49 };
351 int ww[NWC];
352 int narg,i,j,wi;
354 /* Create & Position the label */
355 wc[nwcTOGGLE] = xmToggleButtonWidgetClass;
356 wc[nwcBUTTON] = 0;
357 wlab[nwcTOGGLE] = GMXTOGGLE;
358 wlab[nwcBUTTON] = GMXDLG;
360 for(j=0; (j<NWC); j++) {
361 narg = 0;
362 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_POSITION); narg++;
363 XtSetArg(args[narg],XmNleftPosition, left+rleft[j]); narg++;
364 if (j != nwcTOGGLE) {
365 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_POSITION); narg++;
366 XtSetArg(args[narg],XmNrightPosition, left+rright[j]); narg++;
368 if (top == parent) {
369 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_FORM); narg++;
371 else {
372 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_WIDGET); narg++;
373 XtSetArg(args[narg],XmNtopWidget, get_widget(top)); narg++;
375 XtSetArg(args[narg],XmNbottomAttachment, XmATTACH_NONE); narg++;
377 if (j == nwcBUTTON) {
378 ww[j] = add_widget(XmCreateOptionMenu(get_widget(parent),wlab[j],
379 args,narg),desc);
381 else {
382 XtSetArg(args[narg], XmNlabelString, char2xms(label)); narg++;
383 ww[j] = add_widget(XtCreateWidget(wlab[j],wc[j],
384 get_widget(parent),args,narg),desc);
387 /* Create the popup menu father */
388 pd = add_widget(XmCreatePulldownMenu(get_widget(parent),GMXPD,NULL,0),
389 desc);
391 /* Now create the popup menu children */
392 set_windex_popup(pd,TRUE);
393 set_parent(pd,get_widget(ww[nwcBUTTON]));
394 set_widget_other(pd,get_widget(ww[nwcTOGGLE]));
396 for(i=1; (but[i] != NULL); i++) {
397 sprintf(buf,"%s = %s",desc,but[i]);
398 narg = 0;
399 XtSetArg(args[narg],XmNlabelString,char2xms(but[i])); narg++;
400 wi = add_widget(XtCreateWidget(GMXBUTTON,xmPushButtonWidgetClass,
401 get_widget(pd),args,narg),buf);
402 set_parent(wi,get_widget(pd));
405 /* Tell the option menu what to do */
406 XtVaSetValues(get_widget(ww[nwcBUTTON]),
407 /*XmNlabelString, str,*/
408 XmNsubMenuId, get_widget(pd),
409 XmNentryBorder, 2,
410 XmNwhichButton, 1,
411 NULL);
412 *wtextf = ww[nwcBUTTON];
415 static void mk_buttons(int parent,int top,int nb,t_button bbb[])
417 int i,narg,nw,left,right,bw;
418 real dx;
420 nw = 1;
421 dx = (100-(nb+1)*nw)/(real)nb;
422 right = nw;
423 for(i=0; (i<nb); i++) {
424 left = nw*(i+1)+i*dx;
425 right = left+dx;
426 narg = 0;
427 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_WIDGET); narg++;
428 XtSetArg(args[narg],XmNtopWidget, get_widget(top)); narg++;
429 if (i == 0) {
430 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_FORM); narg++;
432 else {
433 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_POSITION); narg++;
434 XtSetArg(args[narg],XmNleftPosition, left); narg++;
436 if (i == nb-1) {
437 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_FORM); narg++;
439 else {
440 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_POSITION); narg++;
441 XtSetArg(args[narg],XmNrightPosition, right); narg++;
443 XtSetArg(args[narg],XmNlabelString,char2xms(bbb[i].label)); narg++;
444 bw = add_widget(XtCreateWidget(GMXBUTTON,xmPushButtonWidgetClass,
445 get_widget(parent),args,narg),
446 bbb[i].desc);
447 XtAddCallback(get_widget(bw),XmNactivateCallback,
448 (XtCallbackProc) bbb[i].cbfn,NULL);
452 static XmString xs_str_array_to_xmstr(char *header,int ndesc,char *desc[])
454 int i;
455 XmString xmstr;
456 char *ptr,*cptr,*nlptr;
458 if (ndesc <= 0)
459 return empty_str;
460 else {
461 xmstr = char2xms(header);
462 for(i=0; (i<ndesc); i++) {
463 xmstr = XmStringConcat(xmstr,XmStringSeparatorCreate());
464 ptr = check_tty(desc[i]);
465 cptr = wrap_lines(ptr,70,0);
466 ptr = cptr;
467 while ((nlptr = strchr(ptr,'\n')) != NULL) {
468 *nlptr='\0';
469 xmstr = XmStringConcat(xmstr,char2xms(ptr));
470 xmstr = XmStringConcat(xmstr,XmStringSeparatorCreate());
471 ptr = nlptr+1;
472 while (*ptr == '\n')
473 ptr++;
475 xmstr = XmStringConcat(xmstr,char2xms(ptr));
476 sfree(cptr);
478 return xmstr;
482 static windex mk_separator(windex parent,windex topw)
484 int narg,sep;
486 narg = 0;
487 if (nwidget() > 0) {
488 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_WIDGET); narg++;
489 if (topw < 0)
490 topw = nwidget()-1;
491 XtSetArg(args[narg],XmNtopWidget, get_widget(topw)); narg++;
493 else {
494 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_FORM); narg++;
496 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_FORM); narg++;
497 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_FORM); narg++;
499 sep = add_widget(XtCreateWidget(GMXSEP,xmSeparatorWidgetClass,
500 get_widget(parent),args,narg),NULL);
502 set_top_windex(sep);
504 return sep;
507 static int mk_helplabel(int parent,int top)
509 int narg;
510 char buf[] = "Place the mouse over an item to get information";
512 desc_str = char2xms(buf);
513 narg = 0;
514 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_WIDGET); narg++;
515 XtSetArg(args[narg],XmNtopWidget, get_widget(top)); narg++;
516 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_FORM); narg++;
517 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_FORM); narg++;
518 XtSetArg(args[narg],XmNalignment, XmALIGNMENT_BEGINNING); narg++;
519 XtSetArg(args[narg],XmNlabelString, desc_str); narg++;
521 return add_widget(XmCreateLabel(get_widget(parent),GMXDESC,args,narg),NULL);
524 static windex mk_filedlgs(int parent,int top,int nfile,
525 t_filenm fnm[],int fnm_index[])
527 enum { nwcLABEL, nwcTEXT, nwcFDLG, NWC };
528 WidgetClass wc[NWC];
529 int left[NWC] = { 1, 12, 39 };
530 int right[NWC] = { 11, 38, 49 };
531 char **wname;
532 int i,j,ftp,narg,dx,www[NWC];
533 Widget topw;
534 char *fn,dbuf[256];
536 wc[nwcTEXT] = xmTextFieldWidgetClass;
537 wc[nwcFDLG] = xmPushButtonWidgetClass;
539 /* Make the compiler happy */
540 topw = (Widget) 0;
542 snew(wname,NWC);
543 wname[nwcLABEL] = GMXTOGGLE;
544 wname[nwcTEXT] = GMXEDIT;
545 wname[nwcFDLG] = GMXBUTTON;
546 for(i=0; (i<nfile); i++) {
547 ftp = fnm[i].ftp;
548 dx = (i % 2)*50;
549 sprintf(dbuf,"%s [%s]",ftp2desc(ftp),fileopt(fnm[i].flag));
550 if ((fn = strrchr(fnm[i].fn,'/')) == NULL)
551 fn = fnm[i].fn;
552 else
553 fn++;
555 if (is_optional(&(fnm[i])))
556 wc[nwcLABEL] = xmToggleButtonWidgetClass;
557 else
558 wc[nwcLABEL] = xmLabelWidgetClass;
560 for(j=0; (j<NWC); j++) {
561 narg = 0;
562 if (i < 2) {
563 if (top == parent) {
564 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_FORM); narg++;
566 else {
567 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_WIDGET); narg++;
568 XtSetArg(args[narg],XmNtopWidget, get_widget(top)); narg++;
571 else {
572 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_WIDGET); narg++;
573 XtSetArg(args[narg],XmNtopWidget, topw); narg++;
576 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_POSITION); narg++;
577 XtSetArg(args[narg],XmNleftPosition, dx+left[j]); narg++;
580 if (j != nwcLABEL) {
581 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_POSITION); narg++;
582 XtSetArg(args[narg],XmNrightPosition, dx+right[j]); narg++;
584 switch (j) {
585 case nwcLABEL:
586 XtSetArg(args[narg],XmNlabelString, char2xms(fnm[i].opt)); narg++;
587 break;
588 case nwcFDLG:
589 XtSetArg(args[narg],XmNlabelString, char2xms("Browse")); narg++;
590 break;
591 case nwcTEXT:
592 XtSetArg(args[narg],XmNvalue, fnm[i].fn); narg++;
593 break;
595 www[j] = add_widget(XtCreateWidget(wname[j],wc[j],
596 get_widget(parent),args,narg),dbuf);
598 fnm_index[i] = www[nwcTEXT];
599 set_windex_orignm(www[nwcTEXT],fnm[i].fn);
600 set_widget_ftp(www[nwcFDLG],ftp);
601 set_widget_other(www[nwcFDLG],get_widget(www[nwcTEXT]));
603 if (is_optional(&(fnm[i])))
604 set_widget_other(www[nwcTEXT],get_widget(www[nwcLABEL]));
606 XtAddCallback(get_widget(www[nwcFDLG]),XmNactivateCallback,
607 (XtCallbackProc) file_callback,NULL);
608 if ((i % 2) == 1)
609 topw = get_widget(www[nwcTEXT]);
611 sfree(wname);
613 if (nfile > 0)
614 return mk_separator(parent,nwidget()-2);
615 else
616 return 0;
619 static bool motif_hidden(t_pargs *pa)
621 return (is_hidden(pa) ||
622 (strcmp(pa->option,"-X") == 0) ||
623 (strcmp(pa->option,"-h") == 0));
626 static windex mk_pargs(int parent,int npargs,t_pargs pa[],int pa_index[],
627 windex topw)
629 /**************************************************************
631 * Create all the children in two passes:
632 * 1st the checkboxes (etBOOL variables)
633 * 2nd the editable fields
634 * Return the index of the separator (or the last created widget)
636 **************************************************************/
637 int icb,i,npa,dummy,separator,nbool,nedit,nenum,nelem,left;
638 real bwidth;
639 char buf[132],descbuf[132];
641 /* Make the compiler happy */
642 separator = 0;
644 /* First round just count booleans and editors */
645 nbool = nedit = nenum = 0;
646 for(i=0; (i<npargs); i++) {
647 if (!motif_hidden(&(pa[i]))) {
648 if (pa[i].type == etBOOL)
649 nbool++;
650 else if (pa[i].type == etENUM)
651 nenum++;
652 else
653 nedit++;
656 if (nbool > 6)
657 nbool = 6;
658 bwidth = (100.0/nbool);
660 if (nenum > 2)
661 nenum = 2;
663 set_top_windex(topw);
665 for(icb=0; (icb<3); icb++) {
666 new_windex_row();
667 npa = 0;
668 for(i=0; (i<npargs); i++) {
669 topw = top_windex();
670 nelem = 0;
671 if (!motif_hidden(&(pa[i]))) {
672 sprintf(descbuf,"%s (%s)",pa[i].desc,argtp[pa[i].type]);
673 switch (pa[i].type) {
674 case etBOOL:
675 if (icb == 0) {
676 nelem = nbool;
677 left = ((npa % nbool)*bwidth)+0.5;
678 if (debug)
679 fprintf(debug,"%s,%d: nbool %d, bwidth %g, left %d, topw %d\n",
680 __FILE__,__LINE__,nbool,bwidth,left,topw);
681 pa_index[i] = mk_toggle(parent,pa[i].option,topw,
682 left,*(pa[i].u.b),descbuf);
684 break;
685 case etENUM:
686 if (icb == 1) {
687 nelem = nenum;
688 left = (npa % nenum)*50;
689 mk_enumerated(parent,topw,left,&dummy,&(pa_index[i]),
690 pa[i].option,pa[i].u.c,descbuf);
692 break;
693 default:
694 if (icb == 2) {
695 nelem = 2;
696 switch (pa[i].type) {
697 case etREAL:
698 sprintf(buf,"%g",*(pa[i].u.r));
699 break;
700 case etRVEC:
701 sprintf(buf,"%g %g %g",(*pa[i].u.rv)[XX],
702 (*pa[i].u.rv)[YY],(*pa[i].u.rv)[ZZ]);
703 break;
704 case etINT:
705 sprintf(buf,"%d",*(pa[i].u.i));
706 break;
707 case etSTR:
708 if (*(pa[i].u.c) != NULL)
709 strcpy(buf,*(pa[i].u.c));
710 else
711 buf[0] = '\0';
712 break;
714 if (debug)
715 fprintf(debug,"%s,%d: buf = %s\n",__FILE__,__LINE__,buf);
716 left = (npa % nelem)*50;
717 mk_editor(i,parent,topw,left,pa[i].option,buf,descbuf);
719 break;
722 if (nelem) {
723 npa ++;
724 set_top_windex(pa_index[i]);
725 if ((npa % nelem) == 0)
726 new_windex_row();
730 if (npa > 0) {
731 new_windex_row();
732 separator = mk_separator(parent,top_windex());
735 return separator;
738 static void append_str(char **buf,int *blen,int *maxlen,char *str,
739 int indent)
741 #define DELTA 256
742 int i,slen,width=80;
743 char *ptr,*nptr;
745 ptr = check_tty(str);
746 if (indent > 0) {
747 slen=strlen(ptr);
748 snew(nptr,slen+8);
749 sprintf(nptr,"* %s",ptr);
750 str = wrap_lines(nptr,width,indent);
752 else
753 str = wrap_lines(ptr,width,indent);
755 /*while ((ptr = strstr(str,"\n\n")) != 0)
756 *ptr = ' ';
758 slen = strlen(str);
760 while (*blen+slen+1 > *maxlen) {
761 srenew((*buf),*maxlen+DELTA);
762 for(i=(*maxlen); (i<(*maxlen)+DELTA); i++)
763 (*buf)[i] = '\0';
764 (*maxlen) += DELTA;
766 strcat(*buf,str);
767 strcat(*buf,"\n");
768 *blen+=slen+1;
769 #undef DELTA
772 static char *concat_str(char *dtitle,int ndesc,char *desc[],
773 char *btitle,int nbugs,char *bugs[])
775 char *descer;
776 char *ptr = NULL;
777 char *buf;
778 int i,blen=0,maxlen=0,dlen;
780 append_str(&ptr,&blen,&maxlen,dtitle,0);
781 buf=strdup(dtitle);
782 for(i=0; (buf[i] != '\0'); i++)
783 buf[i] = '-';
784 append_str(&ptr,&blen,&maxlen,buf,0);
785 sfree(buf);
786 if (ndesc == 0)
787 append_str(&ptr,&blen,&maxlen,"none?",0);
789 /* Count the length of the strings together */
790 dlen = 0;
791 for(i=0; (i<ndesc); i++) {
792 dlen += strlen(desc[i])+1;
794 snew(descer,dlen+1);
795 for(i=0; (i<ndesc); i++) {
796 strcat(descer,desc[i]);
797 if (i < ndesc-1)
798 strcat(descer," ");
800 append_str(&ptr,&blen,&maxlen,descer,0);
801 sfree(descer);
802 if (nbugs > 0) {
803 append_str(&ptr,&blen,&maxlen," ",0);
804 append_str(&ptr,&blen,&maxlen,btitle,0);
805 buf=strdup(btitle);
806 for(i=0; (buf[i] != '\0'); i++)
807 buf[i] = '-';
808 append_str(&ptr,&blen,&maxlen,buf,0);
809 sfree(buf);
811 for(i=0; (i<nbugs); i++) {
812 append_str(&ptr,&blen,&maxlen,bugs[i],2);
814 return ptr;
817 static int low_mk_help(Widget parent,
818 char *dtitle,int ndesc,char *desc[],
819 char *btitle,int nbugs,char *bugs[],
820 XtCallbackProc ok_callback)
822 windex text,sep,ok,sw;
823 char buf[256],*ptr;
824 int narg,awin;
826 /* Create the mother of all help windows */
827 sprintf(buf,"Gromacs Help - %s",ShortProgram());
828 narg = 0;
829 XtSetArg(args[narg],XmNdialogTitle,char2xms(buf)); narg++;
830 awin = add_widget(XmCreateFormDialog(parent,GMXHELP,args,narg),buf);
832 ptr = concat_str(dtitle,ndesc,desc,btitle,nbugs,bugs);
834 /* Now create the contents */
835 narg = 0;
836 XtSetArg(args[narg],XmNheight, 480); narg++;
837 XtSetArg(args[narg],XmNwidth, 570); narg++;
838 XtSetArg(args[narg],XmNeditMode, XmMULTI_LINE_EDIT); narg++;
839 XtSetArg(args[narg],XmNeditable, FALSE); narg++;
840 XtSetArg(args[narg],XmNvalue, ptr); narg++;
841 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_FORM); narg++;
842 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_FORM); narg++;
843 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_FORM); narg++;
844 XtSetArg(args[narg],XmNscrollingPolicy, XmAUTOMATIC); narg++;
845 XtSetArg(args[narg],XmNscrollBarDisplayPolicy,XmAUTOMATIC); narg++;
846 text = add_widget(XmCreateScrolledText(get_widget(awin),GMXHELP,
847 args,narg),
848 "There is supposed to be useful information in the help window");
849 sw = add_widget(XtParent(get_widget(text)),NULL);
850 sep = mk_separator(awin,sw);
852 narg = 0;
853 XtSetArg(args[narg],XmNtopAttachment, XmATTACH_WIDGET); narg++;
854 XtSetArg(args[narg],XmNtopWidget, get_widget(sep)); narg++;
855 XtSetArg(args[narg],XmNleftAttachment, XmATTACH_FORM); narg++;
856 XtSetArg(args[narg],XmNrightAttachment, XmATTACH_FORM); narg++;
857 XtSetArg(args[narg],XmNalignment, XmALIGNMENT_CENTER); narg++;
858 XtSetArg(args[narg],XmNbottomAttachment,XmATTACH_FORM); narg++;
859 XtSetArg(args[narg],XmNlabelString, char2xms("OK")); narg++;
860 ok = add_widget(XmCreatePushButton(get_widget(awin),
861 GMXBUTTON,args,narg),
862 "Press OK to close the helpwindow");
863 XtAddCallback(get_widget(ok),XmNactivateCallback,ok_callback,NULL);
865 /* Now manage all except the mother of all help windows */
866 XtManageChild(get_widget(ok));
867 XtManageChild(get_widget(sw));
868 XtManageChild(get_widget(text));
869 XtManageChild(get_widget(sep));
871 return awin;
874 static int mk_help(Widget base,int ndesc,char *desc[],int nbugs,char *bugs[])
876 return low_mk_help(base,"DESCRIPTION:",ndesc,desc,
877 "DIAGNOSTICS:",nbugs,bugs,(XtCallbackProc) help_ok_callback);
880 static int mk_about(Widget base)
882 char *about[] = {
883 "Starting with version 2.0 GROMACS has an X/Motif graphical user interface (GUI) to all",
884 "programs. The command line interface is translated automatically into",
885 "a dialog box which should make life a bit easier for those new to the",
886 "programs. A drawback of this approach is that the options are usually",
887 "short, and therefore not very desriptive. In the GUI there is a line with",
888 "extra information at the bottom, which informs you about the option under",
889 "the mouse cursor.[PAR]",
890 "Note that in the following description all possible elements of the GUI",
891 "are described, but your program need not have all these option types.[PAR]",
892 "In the upper pane of the dialog box you find the file options. These can",
893 "be manually edited or using a File selector box under the [BB]Browse[bb]",
894 "button. Note that some files are optional, only if you tick the box before the",
895 "option the program will actually use the file. If you use the File selector",
896 "box to select a file the option will be used automatically. If you change your",
897 "mind about the option you can turn it off again using the tick box.[PAR]",
898 "In the second pane of the dialog box you will find a number of Toggle buttons",
899 "with which you can turn flags on and off.[PAR]",
900 "In the third pane of the dialog box there are options which can take",
901 "a limited set of values (enumerated in programmers jargon). This is implemented",
902 "in the GUI using a popup menu.[PAR]",
903 "In the fourth pane you find the options which require you to type (yuckie!)",
904 "a numeric or textual argument (note that the description window indicates",
905 "which kind of argument). The validity of what you type is *not* checked",
906 "by the GUI as this does not know what the options mean. Instead the program",
907 "using the GUI will (hopefully) verify that your input is meaningful.[PAR]",
908 "In the fifth pane you find the usual buttons, [BB]OK[bb], [BB]Cancel[bb],",
909 "[BB]Help[bb], and [BB]About[bb] which presumably don't need any explanation.[PAR]",
910 "The GUI was written by David van der Spoel (comments to spoel@xray.bmc.uu.se)[PAR]",
911 "And hey:[BR]",
912 NULL
914 #define NABOUT asize(about)
916 static char *mbugs[] = {
917 "The file selector box generates a core dump under Linux/lesstif0.86",
918 "The file selector box does not work with multiple file selections yet",
919 "It took about 1500 lines of pretty ugly C code to get this dialog box working"
922 about[NABOUT-1] = cool_quote();
924 return low_mk_help(base,
925 "ABOUT THE GROMACS MOTIF USER INTERFACE",asize(about),about,
926 "PROBLEMS IN THE GUI",asize(mbugs),mbugs,
927 (XtCallbackProc) about_ok_callback);
930 static void mk_fdlg(Widget base)
932 int narg;
934 narg = 0;
935 XtSetArg(args[narg],XmNdialogTitle,char2xms("GMX File selector")); narg++;
936 fdlgw = add_widget(XmCreateFileSelectionDialog(base,GMXFILE,args,narg),NULL);
937 XtAddCallback(get_widget(fdlgw),XmNokCallback,
938 (XtCallbackProc) file_ok_callback,NULL);
939 XtAddCallback(XmFileSelectionBoxGetChild(get_widget(fdlgw),
940 XmDIALOG_CANCEL_BUTTON),
941 XmNactivateCallback,
942 (XtCallbackProc) file_cancel_callback,NULL);
943 XtUnmanageChild(XmFileSelectionBoxGetChild(get_widget(fdlgw),
944 XmDIALOG_HELP_BUTTON));
946 /* Make the filter fixed... */
947 narg = 0;
948 XtSetArg(args[narg],XmNeditable,False); narg++;
949 XtSetValues(XmFileSelectionBoxGetChild(get_widget(fdlgw),
950 XmDIALOG_FILTER_TEXT),args,narg);
953 static void mk_gui(Widget gmxBase,
954 int nfile,t_filenm fnm[],int npargs,t_pargs pa[],
955 int ndesc,char *desc[],int nbugs,char *bugs[])
957 /****************************************************************
959 * M A K E G U I F O R G R O M A C S
961 ****************************************************************/
962 t_button bbb[] = {
963 { "OK", "Press OK to accept current settings and continue",
964 &ok_callback },
965 { "Cancel", "Press Cancel to quit the program",
966 &cancel_callback },
967 { "Help", "Press Help for more information about the program",
968 &help_callback },
969 { "About", "Press About for information about using this dialog box",
970 &about_callback },
972 #define NBUT asize(bbb)
973 int sep1,sep2,widg0;
974 int i;
976 /* Make the compiler happy */
977 sep1 = 0;
979 /* Create the help window */
980 helpw = mk_help(gmxBase,ndesc,desc,nbugs,bugs);
982 /* Create the about window */
983 aboutw = mk_about(gmxBase);
985 /* Create the file selector box */
986 mk_fdlg(gmxBase);
988 /* Create the dialog box! */
989 gmxDialog = add_widget(XmCreateForm(gmxBase,GMXDLG,NULL,0),NULL);
990 XtManageChild(get_widget(gmxDialog));
992 widg0 = nwidget();
994 /* Create buttons for file dialogboxes */
995 if (nfile > 0) {
996 snew(fnm_index,nfile);
997 sep1 = mk_filedlgs(gmxDialog,gmxDialog,nfile,fnm,fnm_index);
1000 /* Create the checkboxes and editable fields */
1001 if (npargs > 0) {
1002 snew(pa_index,npargs);
1003 snew(pa_set_index,npargs);
1004 sep1 = mk_pargs(gmxDialog,npargs,pa,pa_index,sep1);
1006 else
1007 sep1 = nwidget()-1;
1009 /* Create & count the buttons */
1010 mk_buttons(gmxDialog,sep1,NBUT,bbb);
1012 /* Create & Position the separator */
1013 sep2 = mk_separator(gmxDialog,-1);
1015 /* Create help label */
1016 descw = mk_helplabel(gmxDialog,sep2);
1018 /* Make eventhandlers for the help line */
1019 mk_desc_handlers();
1021 /* Give the children a father or mother */
1022 for(i=widg0; (i<nwidget()); i++)
1023 if (!get_windex_popup(i))
1024 XtManageChild(get_widget(i));
1027 /***************************************************************************
1029 * M A I N L O O P
1031 ***************************************************************************/
1033 static void MyMainLoop(XtAppContext appcontext,Widget gmxBase,
1034 int nfile,t_filenm fnm[],int npargs,t_pargs pa[])
1036 int i,narg;
1037 Widget www,wsub;
1038 XEvent event;
1039 XmString xms;
1040 Boolean xmrb,bbb;
1041 char *fn,buf[256],*ptr;
1042 double ddd,dx,dy,dz;
1043 int iii;
1045 while (!bDone) {
1046 XtAppNextEvent(appcontext,&event);
1047 XtDispatchEvent(&event);
1049 /* Extract all the information from the X widgets */
1050 for(i=0; (i<nfile); i++) {
1051 www = get_widget(fnm_index[i]);
1052 narg = 0;
1053 XtSetArg(args[narg], XmNvalue, &fn); narg++;
1054 XtGetValues(www,args,narg);
1055 sprintf(buf,"%s%s",get_widget_dir(fnm_index[i]),fn);
1056 XtFree(fn);
1057 sfree(fnm[i].fn);
1058 fnm[i].fn = strdup(buf);
1059 if (is_optional(&(fnm[i]))) {
1060 www = get_widget_other(fnm_index[i],FALSE);
1061 if (www != 0) {
1062 narg = 0;
1063 XtSetArg(args[narg],XmNset,&xmrb); narg++;
1064 XtGetValues(www,args,narg);
1065 if (xmrb)
1066 fnm[i].flag = fnm[i].flag | ffSET;
1068 else
1069 fatal_error(0,"No toggle button for optional file (option %s)",
1070 fnm[i].opt);
1071 if (strcmp(fnm[i].fn,get_windex_orignm(fnm_index[i])) != 0) {
1072 if (debug) {
1073 fprintf(debug,"File corr. to option %s has been modified from\n"
1074 "'%s' to '%s'\n",fnm[i].opt,
1075 get_windex_orignm(fnm_index[i]),fnm[i].fn);
1077 fnm[i].flag = fnm[i].flag | ffSET;
1080 if (debug)
1081 fprintf(debug,"%s,%d: File is now %s\n",__FILE__,__LINE__,buf);
1084 for(i=0; (i<npargs); i++) {
1085 if (!is_hidden(&pa[i])) {
1086 if (pa[i].type == etBOOL) {
1087 narg = 0;
1088 XtSetArg(args[narg],XmNset, &bbb); narg++;
1089 XtGetValues(get_widget(pa_index[i]),args,narg);
1090 *(pa[i].u.b) = (bbb == True);
1091 if (debug)
1092 fprintf(debug,"%s,%d: Boolean (windex %d) %s = %s\n",__FILE__,__LINE__,
1093 pa_index[i],pa[i].option,bool_names[*(pa[i].u.b)]);
1095 else {
1096 /* Check whether it is set */
1097 narg = 0;
1098 XtSetArg(args[narg],XmNset, &bbb); narg++;
1099 XtGetValues(get_widget(pa_set_index[i]),args,narg);
1100 pa[i].bSet = (bbb == True);
1102 /* Now extract the value */
1103 if (pa[i].type == etENUM) {
1104 /* First get the selected widget */
1105 narg = 0;
1106 XtSetArg(args[narg],XmNmenuHistory, &wsub); narg++;
1107 XtGetValues(get_widget(pa_index[i]),args,narg);
1108 /* Now get it's label! */
1109 narg = 0;
1110 XtSetArg(args[narg],XmNlabelString, &xms); narg++;
1111 XtGetValues(wsub,args,narg);
1112 ptr = xms2char(xms);
1114 else {
1115 narg = 0;
1116 XtSetArg(args[narg],XmNvalue, &ptr); narg++;
1117 XtGetValues(get_widget(pa_index[i]),args,narg);
1119 if (debug)
1120 fprintf(debug,"%s,%d: I found option %s value %s\n",
1121 __FILE__,__LINE__,pa[i].option,ptr);
1122 switch (pa[i].type) {
1123 case etREAL:
1124 if (sscanf(ptr,"%lf",&ddd) != 1)
1125 fprintf(stderr,"Warning: invalid entry (%s) for real value %s, using default %g\n",
1126 ptr,pa[i].option,*(pa[i].u.r));
1127 else
1128 *pa[i].u.r = ddd;
1129 break;
1130 case etRVEC:
1131 if (sscanf(ptr,"%lf%lf%lf",&dx,&dy,&dz) != 3)
1132 fprintf(stderr,"Warning: invalid entry (%s) for rvec value %s, using default (%g,%g,%g)\n",
1133 ptr,pa[i].option,(*pa[i].u.rv)[XX],(*pa[i].u.rv)[YY],
1134 (*pa[i].u.rv)[ZZ]);
1135 else {
1136 (*pa[i].u.rv)[XX] = dx;
1137 (*pa[i].u.rv)[YY] = dy;
1138 (*pa[i].u.rv)[ZZ] = dz;
1140 break;
1141 case etINT:
1142 if (sscanf(ptr,"%d",&iii) != 1)
1143 fprintf(stderr,"Warning: invalid entry (%s) for integer value %s, using default %d\n",
1144 ptr,pa[i].option,*(pa[i].u.i));
1145 else
1146 *pa[i].u.i = iii;
1147 break;
1148 case etSTR:
1149 *(pa[i].u.c) = strdup(ptr);
1150 break;
1151 case etENUM:
1152 pa[i].u.c[0] = strdup(ptr);
1153 break;
1155 sfree(ptr);
1159 /* Clean up windows */
1160 XtUnmanageChild(get_widget(gmxDialog));
1161 XtUnmanageChild(get_widget(fdlgw));
1162 XtUnmanageChild(get_widget(helpw));
1163 XtUnrealizeWidget(gmxBase);
1164 XtDestroyApplicationContext(appcontext);
1167 void gmx_gui(int *argc,char *argv[],
1168 int nfile,t_filenm fnm[],int npargs,t_pargs pa[],
1169 int ndesc,char *desc[],int nbugs,char *bugs[])
1171 Widget gmxBase;
1172 XtAppContext appcontext;
1173 String Fallbacks[] = {
1174 "*gmx*background: lightgrey",
1175 /*"*gmxdlg.background: lightgrey",
1176 "*gmxbutton.background: lightskyblue",
1177 "*gmxtoggle.background: lightgrey",
1178 "*gmxedit.background: lightgoldenrod1",
1179 "*gmxdesc.background: lightsalmon1",
1180 "*gmxsep.background: darkgrey",
1181 "*gmxhelp.background: lightgoldenrod1",
1182 "*gmxhelpSW.background: lightgrey",
1183 "*gmxhelpSW.*.background: lightgrey",
1184 "*gmxfile.*.background: lightgrey",
1185 "*gmxfile.Text.background: lightgoldenrod1",*/
1186 NULL
1189 /* Initialize toolkit and parse command line options. */
1190 gmxBase = XtOpenApplication(&appcontext,"gmx",NULL,0,argc,argv,Fallbacks,
1191 applicationShellWidgetClass,NULL,0);
1193 mk_gui(gmxBase,nfile,fnm,npargs,pa,ndesc,desc,nbugs,bugs);
1194 XtRealizeWidget(gmxBase);
1195 MyMainLoop(appcontext,gmxBase,nfile,fnm,npargs,pa);