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