Merge release-4-6 into master
[alexxy/gromacs.git] / src / programs / view / xdlghi.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2013, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * Gyas ROwers Mature At Cryogenic Speed
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <string.h>
40
41 #include "gmx_fatal.h"
42 #include "string2.h"
43 #include "sysstuff.h"
44 #include "smalloc.h"
45 #include "macros.h"
46 #include "xutil.h"
47 #include "xdlghi.h"
48 #include "fgrid.h"
49
50 t_dlgitem **CreateRadioButtonGroup(t_x11 *x11, char *szTitle,
51                                    t_id GroupID, int nrb, t_id rb[],
52                                    int nSelect,
53                                    char *szRB[], int x0, int y0)
54 /* This routine creates a radio button group at the
55  * specified position. The return values is a pointer to an
56  * array of dlgitems, the array has length (nrb+1) with the +1
57  * because of the groupbox.
58  * nSelect is the ordinal of the selected button.
59  */
60 {
61     t_dlgitem **dlgitem;
62     int         x, y, w;
63     int         i;
64
65     snew(dlgitem, nrb+1);
66     dlgitem[0] = CreateGroupBox(x11, szTitle, GroupID, nrb, rb, x0, y0, 0, 0, 0);
67     x          = x0+2*OFFS_X;
68     y          = dlgitem[0]->win.y+dlgitem[0]->win.height;
69     w          = 0;
70     for (i = 0; (i < nrb); i++)
71     {
72         dlgitem[i+1] = CreateRadioButton(x11, szRB[i], (i == nSelect),
73                                          rb[i], GroupID, x, y, 0, 0, 0);
74         y += dlgitem[i+1]->win.height+OFFS_Y;
75         w  = std::max(w, dlgitem[i+1]->win.width);
76     }
77     for (i = 0; (i < nrb); i++)
78     {
79         dlgitem[i+1]->win.width = w;
80     }
81     dlgitem[0]->win.width  = w+4*OFFS_X;
82     dlgitem[0]->win.height = y-y0;
83
84     return dlgitem;
85 }
86
87 t_dlgitem **CreateDlgitemGroup(t_x11 *x11, const char *szTitle,
88                                t_id GroupID, int x0, int y0,
89                                int nitem, ...)
90 /* This routine creates a dlgitem group at the
91  * specified position. The return values is a pointer to an
92  * array of dlgitems, the array has length (nitem+1) with the +1
93  * because of the groupbox.
94  */
95 {
96     va_list       ap;
97
98     t_dlgitem   **dlgitem;
99     t_id         *ids;
100     edlgitem      edlg;
101     char         *name;
102     bool          bBool;
103     Pixmap        pm;
104     int           nlines, buflen;
105     char         *buf, **lines;
106     int           x, y, w, i;
107
108     va_start(ap, nitem);
109
110     snew(dlgitem, nitem+1);
111     snew(ids, nitem);
112     x          = x0+2*OFFS_X;
113     dlgitem[0] = CreateGroupBox(x11, szTitle, GroupID, nitem, ids, x0, y0, 0, 0, 0);
114     y          = dlgitem[0]->win.y+dlgitem[0]->win.height;
115     w          = 0;
116     for (i = 0; (i < nitem); i++)
117     {
118         edlg   = (edlgitem)va_arg(ap, int);
119         ids[i] = va_arg(ap, int);
120         switch (edlg)
121         {
122             case edlgBN:
123                 name         = va_arg(ap, char *);
124                 bBool        = va_arg(ap, int);
125                 dlgitem[i+1] = CreateButton(x11, name, bBool, ids[i], GroupID, x, y, 0, 0, 0);
126                 break;
127             case edlgRB:
128                 name         = va_arg(ap, char *);
129                 bBool        = va_arg(ap, int);
130                 dlgitem[i+1] = CreateRadioButton(x11, name, bBool, ids[i], GroupID, x, y, 0, 0, 0);
131                 break;
132             case edlgCB:
133                 name         = va_arg(ap, char *);
134                 bBool        = va_arg(ap, int);
135                 dlgitem[i+1] = CreateCheckBox(x11, name, bBool, ids[i], GroupID, x, y, 0, 0, 0);
136                 break;
137             case edlgPM:
138                 pm           = va_arg(ap, Pixmap);
139                 dlgitem[i+1] = CreatePixmap(pm, ids[i], GroupID, x, y, 0, 0, 0);
140                 break;
141             case edlgST:
142                 nlines       = va_arg(ap, int);
143                 lines        = va_arg(ap, char **);
144                 dlgitem[i+1] = CreateStaticText(x11, nlines, lines, ids[i], GroupID,
145                                                 x, y, 0, 0, 0);
146                 break;
147             case edlgET:
148                 name         = va_arg(ap, char *);
149                 buflen       = va_arg(ap, int);
150                 buf          = va_arg(ap, char *);
151                 dlgitem[i+1] = CreateEditText(x11, name, buflen, buf, ids[i],
152                                               GroupID, x, y, 0, 0, 0);
153                 break;
154             case edlgGB:
155             default:
156                 gmx_fatal(FARGS, "Invalid dlgitem type: %d\n", edlg);
157         }
158         y += dlgitem[i+1]->win.height+OFFS_Y;
159         w  = std::max(w, dlgitem[i+1]->win.width);
160     }
161     va_end(ap);
162     sfree(dlgitem[0]->u.groupbox.item);
163     sfree(dlgitem[0]->win.text);
164     dlgitem[0] = CreateGroupBox(x11, szTitle, GroupID, nitem, ids, x0, y0, 0, 0, 0);
165     for (i = 0; (i < nitem); i++)
166     {
167         dlgitem[i+1]->win.width = w;
168     }
169     dlgitem[0]->win.width  = w+4*OFFS_X;
170     dlgitem[0]->win.height = y-y0;
171     return dlgitem;
172 }
173
174 static void AddDlgItemGroups(t_dlg *dlg, int gridx, int gridy,
175                              t_dlgitemlist **grid, bool bAutoPosition)
176 {
177     t_dlgitemlist *item;
178     int            x1, y1, w1, h1;
179     int            x, y, dw, dh;
180     float          w, h;
181
182     w = h = 0;
183     for (x = 0; (x < gridx); x++)
184     {
185         for (y = 0; (y < gridy); y++)
186         {
187             item = &(grid[x][y]);
188             if (item->nitem)
189             {
190                 if (!item->list)
191                 {
192                     printf("Error: empty list with non-empty nitem (%d)\n", item->nitem);
193                     printf("       at grid point: %d,%d\n", x, y);
194                     printf("       with size: %dx%d\n", item->w, item->h);
195                     exit(1);
196                 }
197                 else
198                 {
199                     AddDlgItems(dlg, item->nitem, item->list);
200                     dw = item->w;
201                     dh = item->h;
202                     w  = std::max(w, ((float) QueryDlgItemW(dlg, item->list[0]->ID))/dw);
203                     h  = std::max(h, ((float) QueryDlgItemH(dlg, item->list[0]->ID))/dh);
204                 }
205             }
206         }
207     }
208     w1 = gridx*w;
209     h1 = gridy*h;
210     SetDlgSize(dlg, w1, h1, bAutoPosition);
211 #ifdef DEBUG
212     printf("Dimensions of grid cell: %8.3f x %8.3f\n", w, h);
213     printf("Dimensions of window:    %d x %d\n", w1, h1);
214 #endif
215
216     for (x = 0; (x < gridx); x++)
217     {
218         for (y = 0; (y < gridy); y++)
219         {
220             item = &(grid[x][y]);
221             if (item->nitem)
222             {
223                 x1 = x*w;
224                 y1 = y*h;
225                 w1 = item->w*w;
226                 h1 = item->h*h;
227 #ifdef DEBUG
228                 printf("New size: %d x %d at %d, %d\n", w1, h1, x1, y1);
229 #endif
230                 SetDlgItemSize(dlg, item->list[0]->ID, w1, h1);
231                 SetDlgItemPos(dlg, item->list[0]->ID, x1, y1);
232             }
233         }
234     }
235 }
236
237 static t_dlgitemlist **NewDlgitemList(int w, int h)
238 {
239     int             i, j;
240     t_dlgitemlist **grid;
241
242     snew(grid, w);
243     for (i = 0; (i < w); i++)
244     {
245         snew(grid[i], h);
246         for (j = 0; (j < h); j++)
247         {
248             grid[i][j].nitem = 0;
249             grid[i][j].list  = NULL;
250         }
251     }
252     return grid;
253 }
254
255 static void AddListItem(t_dlgitemlist *list, t_dlgitem *item)
256 {
257     srenew(list->list, ++list->nitem);
258     list->list[list->nitem-1] = item;
259 }
260
261 static void AddListFItem(t_x11 *x11, t_dlgitemlist *list,
262                          t_fitem *fitem, t_id GroupID, t_id *ID,
263                          int x, int *y, int *w, bool bUseMon)
264 {
265     int  i, iSel, slen;
266     char buf[STRLEN];
267
268     switch (fitem->edlg)
269     {
270         case edlgBN:
271             AddListItem
272                 (list, CreateButton(x11, fitem->name[0], fitem->bDef, (*ID)++, GroupID,
273                                     x, (*y), 0, 0, 0));
274             break;
275         case edlgRB:
276             strcpy(buf, fitem->def);
277             iSel = -1;
278             for (i = 0; (i < fitem->nname); i++)
279             {
280                 char buf2[100];
281
282                 strcpy(buf2, fitem->name[i]);
283                 buf2[strlen(buf)] = '\0'; /* truncate itemname */
284                 if (gmx_strcasecmp(buf2, buf) == 0)
285                 {
286                     iSel = i;
287                 }
288             }
289
290             for (i = 0; (i < fitem->nname); i++)
291             {
292                 AddListItem(list,
293                             CreateRadioButton(x11, fitem->name[i], (iSel == i),
294                                               (*ID)++, GroupID, x, (*y), 0, 0, 0));
295                 (*y) += list->list[list->nitem-1]->win.height+OFFS_Y;
296                 (*w)  = std::max((*w), list->list[list->nitem-1]->win.width);
297                 SetDlgitemOpts(list->list[list->nitem-1], bUseMon,
298                                fitem->set, fitem->get, fitem->help);
299             }
300             break;
301         case edlgCB:
302         {
303             bool bCheck;
304
305             bCheck = gmx_strcasecmp(fitem->def, "TRUE") == 0;
306             AddListItem(list, CreateCheckBox(x11, fitem->name[0], bCheck,
307                                              (*ID)++, GroupID, x, (*y), 0, 0, 0));
308             break;
309         }
310         case edlgST:
311             AddListItem(list,
312                         CreateStaticText(x11, fitem->nname,
313                                          fitem->name, (*ID)++,
314                                          GroupID, x, (*y), 0, 0, 0));
315             break;
316         case edlgET:
317             slen = strlen(fitem->name[0])+strlen(fitem->def);
318             AddListItem(list, CreateEditText(x11, fitem->name[0], slen, fitem->def,
319                                              (*ID)++, GroupID, x, (*y), 0, 0, 0));
320             break;
321         case edlgPM:
322         case edlgGB:
323         default:
324             gmx_fatal(FARGS, "Invalid list->list type: %d\n", fitem->edlg);
325     }
326     SetDlgitemOpts(list->list[list->nitem-1], bUseMon,
327                    fitem->set, fitem->get, fitem->help);
328
329     if (fitem->edlg != edlgRB)
330     {
331         (*y) += list->list[list->nitem-1]->win.height+OFFS_Y;
332         (*w)  = std::max((*w), list->list[list->nitem-1]->win.width);
333     }
334 }
335
336 static void AddListFGroup(t_x11 *x11, t_dlgitemlist **grid,
337                           t_fgroup *fgroup, t_id *ID, bool bUseMon)
338 {
339     int            i;
340     t_id           GroupID, *ids;
341     t_dlgitemlist *item;
342     int            x, y, w;
343
344     GroupID = (*ID)++;
345     item    = &(grid[fgroup->x][fgroup->y]);
346     AddListItem(item, CreateGroupBox(x11, fgroup->name, GroupID,
347                                      0, NULL, 0, 0, 0, 0, 0));
348     x = 2*OFFS_X;
349     y = item->list[0]->win.y+item->list[0]->win.height;
350     w = 0;
351     for (i = 0; (i < fgroup->nfitem); i++)
352     {
353         AddListFItem(x11, item, fgroup->fitem[i], GroupID, ID, x, &y, &w, bUseMon);
354     }
355
356     w = std::max(w, item->list[0]->win.width+4*OFFS_X);
357     sfree(item->list[0]->u.groupbox.item);
358     sfree(item->list[0]->win.text);
359     snew(ids, item->nitem);
360     for (i = 0; (i < item->nitem-1); i++)
361     {
362         ids[i] = GroupID+i+1;
363     }
364     item->list[0] =
365         CreateGroupBox(x11, fgroup->name, GroupID, item->nitem-1, ids,
366                        2*OFFS_X, 2*OFFS_Y, w+2*OFFS_X, y, 0);
367     sfree(ids);
368     item->w = fgroup->w;
369     item->h = fgroup->h;
370 }
371
372 static void AddListFSimple(t_x11 *x11, t_dlgitemlist **grid,
373                            t_fsimple *fsimple, t_id *ID, bool bUseMon)
374 {
375     t_dlgitemlist *item;
376     int            x, y, w;
377
378     item = &(grid[fsimple->x][fsimple->y]);
379     x    = 0;
380     y    = 0;
381     w    = 0;
382     AddListFItem(x11, item, fsimple->fitem, *ID, ID, x, &y, &w, bUseMon);
383     item->w = fsimple->w;
384     item->h = fsimple->h;
385 }
386
387 t_dlg *ReadDlg(t_x11 *x11, Window Parent, const char *title,
388                const char *infile,
389                int x0, int y0, bool bAutoPosition, bool bUseMon,
390                DlgCallback *cb, void *data)
391 {
392     t_fgrid        *fgrid;
393     t_dlgitemlist **grid;
394     t_dlg          *dlg;
395     int             i;
396     t_id            ID;
397
398     fgrid = FGridFromFile(infile);
399     dlg   = CreateDlg(x11, Parent, title, x0, y0, 0, 0, 0, cb, data);
400     grid  = NewDlgitemList(fgrid->w, fgrid->h);
401     ID    = 0;
402
403     for (i = 0; (i < fgrid->nfgroup); i++)
404     {
405         AddListFGroup(x11, grid, fgrid->fgroup[i], &ID, bUseMon);
406     }
407     for (i = 0; (i < fgrid->nfsimple); i++)
408     {
409         AddListFSimple(x11, grid, fgrid->fsimple[i], &ID, bUseMon);
410     }
411     AddDlgItemGroups(dlg, fgrid->w, fgrid->h, grid, bAutoPosition);
412
413     DoneFGrid(fgrid);
414
415     return dlg;
416 }