aeeb9089c2fd5b2b516d18ad04e87ccee5149b7b
[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,2014, 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 #include "gmxpre.h"
38
39 #include "config.h"
40
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include <algorithm>
45
46 #include "gromacs/legacyheaders/macros.h"
47 #include "xutil.h"
48 #include "xdlghi.h"
49 #include "fgrid.h"
50
51 #include "gromacs/utility/cstringutil.h"
52 #include "gromacs/utility/fatalerror.h"
53 #include "gromacs/utility/smalloc.h"
54
55 t_dlgitem **CreateRadioButtonGroup(t_x11 *x11, char *szTitle,
56                                    t_id GroupID, int nrb, t_id rb[],
57                                    int nSelect,
58                                    char *szRB[], int x0, int y0)
59 /* This routine creates a radio button group at the
60  * specified position. The return values is a pointer to an
61  * array of dlgitems, the array has length (nrb+1) with the +1
62  * because of the groupbox.
63  * nSelect is the ordinal of the selected button.
64  */
65 {
66     t_dlgitem **dlgitem;
67     int         x, y, w;
68     int         i;
69
70     snew(dlgitem, nrb+1);
71     dlgitem[0] = CreateGroupBox(x11, szTitle, GroupID, nrb, rb, x0, y0, 0, 0, 0);
72     x          = x0+2*OFFS_X;
73     y          = dlgitem[0]->win.y+dlgitem[0]->win.height;
74     w          = 0;
75     for (i = 0; (i < nrb); i++)
76     {
77         dlgitem[i+1] = CreateRadioButton(x11, szRB[i], (i == nSelect),
78                                          rb[i], GroupID, x, y, 0, 0, 0);
79         y += dlgitem[i+1]->win.height+OFFS_Y;
80         w  = std::max(w, dlgitem[i+1]->win.width);
81     }
82     for (i = 0; (i < nrb); i++)
83     {
84         dlgitem[i+1]->win.width = w;
85     }
86     dlgitem[0]->win.width  = w+4*OFFS_X;
87     dlgitem[0]->win.height = y-y0;
88
89     return dlgitem;
90 }
91
92 t_dlgitem **CreateDlgitemGroup(t_x11 *x11, const char *szTitle,
93                                t_id GroupID, int x0, int y0,
94                                int nitem, ...)
95 /* This routine creates a dlgitem group at the
96  * specified position. The return values is a pointer to an
97  * array of dlgitems, the array has length (nitem+1) with the +1
98  * because of the groupbox.
99  */
100 {
101     va_list       ap;
102
103     t_dlgitem   **dlgitem;
104     t_id         *ids;
105     edlgitem      edlg;
106     char         *name;
107     bool          bBool;
108     Pixmap        pm;
109     int           nlines, buflen;
110     char         *buf, **lines;
111     int           x, y, w, i;
112
113     va_start(ap, nitem);
114
115     snew(dlgitem, nitem+1);
116     snew(ids, nitem);
117     x          = x0+2*OFFS_X;
118     dlgitem[0] = CreateGroupBox(x11, szTitle, GroupID, nitem, ids, x0, y0, 0, 0, 0);
119     y          = dlgitem[0]->win.y+dlgitem[0]->win.height;
120     w          = 0;
121     for (i = 0; (i < nitem); i++)
122     {
123         edlg   = (edlgitem)va_arg(ap, int);
124         ids[i] = va_arg(ap, int);
125         switch (edlg)
126         {
127             case edlgBN:
128                 name         = va_arg(ap, char *);
129                 bBool        = va_arg(ap, int);
130                 dlgitem[i+1] = CreateButton(x11, name, bBool, ids[i], GroupID, x, y, 0, 0, 0);
131                 break;
132             case edlgRB:
133                 name         = va_arg(ap, char *);
134                 bBool        = va_arg(ap, int);
135                 dlgitem[i+1] = CreateRadioButton(x11, name, bBool, ids[i], GroupID, x, y, 0, 0, 0);
136                 break;
137             case edlgCB:
138                 name         = va_arg(ap, char *);
139                 bBool        = va_arg(ap, int);
140                 dlgitem[i+1] = CreateCheckBox(x11, name, bBool, ids[i], GroupID, x, y, 0, 0, 0);
141                 break;
142             case edlgPM:
143                 pm           = va_arg(ap, Pixmap);
144                 dlgitem[i+1] = CreatePixmap(pm, ids[i], GroupID, x, y, 0, 0, 0);
145                 break;
146             case edlgST:
147                 nlines       = va_arg(ap, int);
148                 lines        = va_arg(ap, char **);
149                 dlgitem[i+1] = CreateStaticText(x11, nlines, lines, ids[i], GroupID,
150                                                 x, y, 0, 0, 0);
151                 break;
152             case edlgET:
153                 name         = va_arg(ap, char *);
154                 buflen       = va_arg(ap, int);
155                 buf          = va_arg(ap, char *);
156                 dlgitem[i+1] = CreateEditText(x11, name, buflen, buf, ids[i],
157                                               GroupID, x, y, 0, 0, 0);
158                 break;
159             case edlgGB:
160             default:
161                 gmx_fatal(FARGS, "Invalid dlgitem type: %d\n", edlg);
162         }
163         y += dlgitem[i+1]->win.height+OFFS_Y;
164         w  = std::max(w, dlgitem[i+1]->win.width);
165     }
166     va_end(ap);
167     sfree(dlgitem[0]->u.groupbox.item);
168     sfree(dlgitem[0]->win.text);
169     dlgitem[0] = CreateGroupBox(x11, szTitle, GroupID, nitem, ids, x0, y0, 0, 0, 0);
170     for (i = 0; (i < nitem); i++)
171     {
172         dlgitem[i+1]->win.width = w;
173     }
174     dlgitem[0]->win.width  = w+4*OFFS_X;
175     dlgitem[0]->win.height = y-y0;
176     return dlgitem;
177 }
178
179 static void AddDlgItemGroups(t_dlg *dlg, int gridx, int gridy,
180                              t_dlgitemlist **grid, bool bAutoPosition)
181 {
182     t_dlgitemlist *item;
183     int            x1, y1, w1, h1;
184     int            x, y, dw, dh;
185     float          w, h;
186
187     w = h = 0;
188     for (x = 0; (x < gridx); x++)
189     {
190         for (y = 0; (y < gridy); y++)
191         {
192             item = &(grid[x][y]);
193             if (item->nitem)
194             {
195                 if (!item->list)
196                 {
197                     printf("Error: empty list with non-empty nitem (%d)\n", item->nitem);
198                     printf("       at grid point: %d,%d\n", x, y);
199                     printf("       with size: %dx%d\n", item->w, item->h);
200                     exit(1);
201                 }
202                 else
203                 {
204                     AddDlgItems(dlg, item->nitem, item->list);
205                     dw = item->w;
206                     dh = item->h;
207                     w  = std::max(w, ((float) QueryDlgItemW(dlg, item->list[0]->ID))/dw);
208                     h  = std::max(h, ((float) QueryDlgItemH(dlg, item->list[0]->ID))/dh);
209                 }
210             }
211         }
212     }
213     w1 = gridx*w;
214     h1 = gridy*h;
215     SetDlgSize(dlg, w1, h1, bAutoPosition);
216 #ifdef DEBUG
217     printf("Dimensions of grid cell: %8.3f x %8.3f\n", w, h);
218     printf("Dimensions of window:    %d x %d\n", w1, h1);
219 #endif
220
221     for (x = 0; (x < gridx); x++)
222     {
223         for (y = 0; (y < gridy); y++)
224         {
225             item = &(grid[x][y]);
226             if (item->nitem)
227             {
228                 x1 = x*w;
229                 y1 = y*h;
230                 w1 = item->w*w;
231                 h1 = item->h*h;
232 #ifdef DEBUG
233                 printf("New size: %d x %d at %d, %d\n", w1, h1, x1, y1);
234 #endif
235                 SetDlgItemSize(dlg, item->list[0]->ID, w1, h1);
236                 SetDlgItemPos(dlg, item->list[0]->ID, x1, y1);
237             }
238         }
239     }
240 }
241
242 static t_dlgitemlist **NewDlgitemList(int w, int h)
243 {
244     int             i, j;
245     t_dlgitemlist **grid;
246
247     snew(grid, w);
248     for (i = 0; (i < w); i++)
249     {
250         snew(grid[i], h);
251         for (j = 0; (j < h); j++)
252         {
253             grid[i][j].nitem = 0;
254             grid[i][j].list  = NULL;
255         }
256     }
257     return grid;
258 }
259
260 static void AddListItem(t_dlgitemlist *list, t_dlgitem *item)
261 {
262     srenew(list->list, ++list->nitem);
263     list->list[list->nitem-1] = item;
264 }
265
266 static void AddListFItem(t_x11 *x11, t_dlgitemlist *list,
267                          t_fitem *fitem, t_id GroupID, t_id *ID,
268                          int x, int *y, int *w, bool bUseMon)
269 {
270     int  i, iSel, slen;
271     char buf[STRLEN];
272
273     switch (fitem->edlg)
274     {
275         case edlgBN:
276             AddListItem
277                 (list, CreateButton(x11, fitem->name[0], fitem->bDef, (*ID)++, GroupID,
278                                     x, (*y), 0, 0, 0));
279             break;
280         case edlgRB:
281             strcpy(buf, fitem->def);
282             iSel = -1;
283             for (i = 0; (i < fitem->nname); i++)
284             {
285                 char buf2[100];
286
287                 strcpy(buf2, fitem->name[i]);
288                 buf2[strlen(buf)] = '\0'; /* truncate itemname */
289                 if (gmx_strcasecmp(buf2, buf) == 0)
290                 {
291                     iSel = i;
292                 }
293             }
294
295             for (i = 0; (i < fitem->nname); i++)
296             {
297                 AddListItem(list,
298                             CreateRadioButton(x11, fitem->name[i], (iSel == i),
299                                               (*ID)++, GroupID, x, (*y), 0, 0, 0));
300                 (*y) += list->list[list->nitem-1]->win.height+OFFS_Y;
301                 (*w)  = std::max((*w), list->list[list->nitem-1]->win.width);
302                 SetDlgitemOpts(list->list[list->nitem-1], bUseMon,
303                                fitem->set, fitem->get, fitem->help);
304             }
305             break;
306         case edlgCB:
307         {
308             bool bCheck;
309
310             bCheck = gmx_strcasecmp(fitem->def, "TRUE") == 0;
311             AddListItem(list, CreateCheckBox(x11, fitem->name[0], bCheck,
312                                              (*ID)++, GroupID, x, (*y), 0, 0, 0));
313             break;
314         }
315         case edlgST:
316             AddListItem(list,
317                         CreateStaticText(x11, fitem->nname,
318                                          fitem->name, (*ID)++,
319                                          GroupID, x, (*y), 0, 0, 0));
320             break;
321         case edlgET:
322             slen = strlen(fitem->name[0])+strlen(fitem->def);
323             AddListItem(list, CreateEditText(x11, fitem->name[0], slen, fitem->def,
324                                              (*ID)++, GroupID, x, (*y), 0, 0, 0));
325             break;
326         case edlgPM:
327         case edlgGB:
328         default:
329             gmx_fatal(FARGS, "Invalid list->list type: %d\n", fitem->edlg);
330     }
331     SetDlgitemOpts(list->list[list->nitem-1], bUseMon,
332                    fitem->set, fitem->get, fitem->help);
333
334     if (fitem->edlg != edlgRB)
335     {
336         (*y) += list->list[list->nitem-1]->win.height+OFFS_Y;
337         (*w)  = std::max((*w), list->list[list->nitem-1]->win.width);
338     }
339 }
340
341 static void AddListFGroup(t_x11 *x11, t_dlgitemlist **grid,
342                           t_fgroup *fgroup, t_id *ID, bool bUseMon)
343 {
344     int            i;
345     t_id           GroupID, *ids;
346     t_dlgitemlist *item;
347     int            x, y, w;
348
349     GroupID = (*ID)++;
350     item    = &(grid[fgroup->x][fgroup->y]);
351     AddListItem(item, CreateGroupBox(x11, fgroup->name, GroupID,
352                                      0, NULL, 0, 0, 0, 0, 0));
353     x = 2*OFFS_X;
354     y = item->list[0]->win.y+item->list[0]->win.height;
355     w = 0;
356     for (i = 0; (i < fgroup->nfitem); i++)
357     {
358         AddListFItem(x11, item, fgroup->fitem[i], GroupID, ID, x, &y, &w, bUseMon);
359     }
360
361     w = std::max(w, item->list[0]->win.width+4*OFFS_X);
362     sfree(item->list[0]->u.groupbox.item);
363     sfree(item->list[0]->win.text);
364     snew(ids, item->nitem);
365     for (i = 0; (i < item->nitem-1); i++)
366     {
367         ids[i] = GroupID+i+1;
368     }
369     item->list[0] =
370         CreateGroupBox(x11, fgroup->name, GroupID, item->nitem-1, ids,
371                        2*OFFS_X, 2*OFFS_Y, w+2*OFFS_X, y, 0);
372     sfree(ids);
373     item->w = fgroup->w;
374     item->h = fgroup->h;
375 }
376
377 static void AddListFSimple(t_x11 *x11, t_dlgitemlist **grid,
378                            t_fsimple *fsimple, t_id *ID, bool bUseMon)
379 {
380     t_dlgitemlist *item;
381     int            x, y, w;
382
383     item = &(grid[fsimple->x][fsimple->y]);
384     x    = 0;
385     y    = 0;
386     w    = 0;
387     AddListFItem(x11, item, fsimple->fitem, *ID, ID, x, &y, &w, bUseMon);
388     item->w = fsimple->w;
389     item->h = fsimple->h;
390 }
391
392 t_dlg *ReadDlg(t_x11 *x11, Window Parent, const char *title,
393                const char *infile,
394                int x0, int y0, bool bAutoPosition, bool bUseMon,
395                DlgCallback *cb, void *data)
396 {
397     t_fgrid        *fgrid;
398     t_dlgitemlist **grid;
399     t_dlg          *dlg;
400     int             i;
401     t_id            ID;
402
403     fgrid = FGridFromFile(infile);
404     dlg   = CreateDlg(x11, Parent, title, x0, y0, 0, 0, 0, cb, data);
405     grid  = NewDlgitemList(fgrid->w, fgrid->h);
406     ID    = 0;
407
408     for (i = 0; (i < fgrid->nfgroup); i++)
409     {
410         AddListFGroup(x11, grid, fgrid->fgroup[i], &ID, bUseMon);
411     }
412     for (i = 0; (i < fgrid->nfsimple); i++)
413     {
414         AddListFSimple(x11, grid, fgrid->fsimple[i], &ID, bUseMon);
415     }
416     AddDlgItemGroups(dlg, fgrid->w, fgrid->h, grid, bAutoPosition);
417
418     DoneFGrid(fgrid);
419
420     return dlg;
421 }