Apply re-formatting to C++ in src/ tree.
[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,2015,2017,2019,2020, 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 "xdlghi.h"
40
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
44
45 #include <algorithm>
46
47 #include "gromacs/utility/cstringutil.h"
48 #include "gromacs/utility/fatalerror.h"
49 #include "gromacs/utility/smalloc.h"
50
51 #include "fgrid.h"
52 #include "xutil.h"
53
54 t_dlgitem** CreateRadioButtonGroup(t_x11* x11,
55                                    char*  szTitle,
56                                    t_id   GroupID,
57                                    int    nrb,
58                                    t_id   rb[],
59                                    int    nSelect,
60                                    char*  szRB[],
61                                    int    x0,
62                                    int    y0)
63 /* This routine creates a radio button group at the
64  * specified position. The return values is a pointer to an
65  * array of dlgitems, the array has length (nrb+1) with the +1
66  * because of the groupbox.
67  * nSelect is the ordinal of the selected button.
68  */
69 {
70     t_dlgitem** dlgitem;
71     int         x, y, w;
72     int         i;
73
74     snew(dlgitem, nrb + 1);
75     dlgitem[0] = CreateGroupBox(x11, szTitle, GroupID, nrb, rb, x0, y0, 0, 0, 0);
76     x          = x0 + 2 * OFFS_X;
77     y          = dlgitem[0]->win.y + dlgitem[0]->win.height;
78     w          = 0;
79     for (i = 0; (i < nrb); i++)
80     {
81         dlgitem[i + 1] = CreateRadioButton(x11, szRB[i], (i == nSelect), rb[i], GroupID, x, y, 0, 0, 0);
82         y += dlgitem[i + 1]->win.height + OFFS_Y;
83         w = std::max(w, dlgitem[i + 1]->win.width);
84     }
85     for (i = 0; (i < nrb); i++)
86     {
87         dlgitem[i + 1]->win.width = w;
88     }
89     dlgitem[0]->win.width  = w + 4 * OFFS_X;
90     dlgitem[0]->win.height = y - y0;
91
92     return dlgitem;
93 }
94
95 t_dlgitem** CreateDlgitemGroup(t_x11* x11, const char* szTitle, t_id GroupID, int x0, int y0, int nitem, ...)
96 /* This routine creates a dlgitem group at the
97  * specified position. The return values is a pointer to an
98  * array of dlgitems, the array has length (nitem+1) with the +1
99  * because of the groupbox.
100  */
101 {
102     va_list ap;
103
104     t_dlgitem** dlgitem;
105     t_id*       ids;
106     edlgitem    edlg;
107     char*       name;
108     bool        bBool;
109     Pixmap      pm;
110     int         nlines, buflen;
111     char *      buf, **lines;
112     int         x, y, w, i;
113
114     va_start(ap, nitem);
115
116     snew(dlgitem, nitem + 1);
117     snew(ids, nitem);
118     x          = x0 + 2 * OFFS_X;
119     dlgitem[0] = CreateGroupBox(x11, szTitle, GroupID, nitem, ids, x0, y0, 0, 0, 0);
120     y          = dlgitem[0]->win.y + dlgitem[0]->win.height;
121     w          = 0;
122     for (i = 0; (i < nitem); i++)
123     {
124         edlg   = (edlgitem)va_arg(ap, int);
125         ids[i] = va_arg(ap, int);
126         switch (edlg)
127         {
128             case edlgBN:
129                 name           = va_arg(ap, char*);
130                 bBool          = va_arg(ap, int);
131                 dlgitem[i + 1] = CreateButton(x11, name, bBool, ids[i], GroupID, x, y, 0, 0, 0);
132                 break;
133             case edlgRB:
134                 name           = va_arg(ap, char*);
135                 bBool          = va_arg(ap, int);
136                 dlgitem[i + 1] = CreateRadioButton(x11, name, bBool, ids[i], GroupID, x, y, 0, 0, 0);
137                 break;
138             case edlgCB:
139                 name           = va_arg(ap, char*);
140                 bBool          = va_arg(ap, int);
141                 dlgitem[i + 1] = CreateCheckBox(x11, name, bBool, ids[i], GroupID, x, y, 0, 0, 0);
142                 break;
143             case edlgPM:
144                 pm             = va_arg(ap, Pixmap);
145                 dlgitem[i + 1] = CreatePixmap(pm, ids[i], GroupID, x, y, 0, 0, 0);
146                 break;
147             case edlgST:
148                 nlines         = va_arg(ap, int);
149                 lines          = va_arg(ap, char**);
150                 dlgitem[i + 1] = CreateStaticText(x11, nlines, lines, ids[i], GroupID, 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], GroupID, x, y, 0, 0, 0);
157                 break;
158             case edlgGB:
159             default: gmx_fatal(FARGS, "Invalid dlgitem type: %d\n", edlg);
160         }
161         y += dlgitem[i + 1]->win.height + OFFS_Y;
162         w = std::max(w, dlgitem[i + 1]->win.width);
163     }
164     va_end(ap);
165     sfree(dlgitem[0]->u.groupbox.item);
166     sfree(dlgitem[0]->win.text);
167     dlgitem[0] = CreateGroupBox(x11, szTitle, GroupID, nitem, ids, x0, y0, 0, 0, 0);
168     for (i = 0; (i < nitem); i++)
169     {
170         dlgitem[i + 1]->win.width = w;
171     }
172     dlgitem[0]->win.width  = w + 4 * OFFS_X;
173     dlgitem[0]->win.height = y - y0;
174     return dlgitem;
175 }
176
177 static void AddDlgItemGroups(t_dlg* dlg, int gridx, int gridy, 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                     std::printf("Error: empty list with non-empty nitem (%d)\n", item->nitem);
195                     std::printf("       at grid point: %d,%d\n", x, y);
196                     std::printf("       with size: %dx%d\n", item->w, item->h);
197                     std::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     std::printf("Dimensions of grid cell: %8.3f x %8.3f\n", w, h);
215     std::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                 std::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  = nullptr;
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
264 AddListFItem(t_x11* x11, t_dlgitemlist* list, t_fitem* fitem, t_id GroupID, t_id* ID, int x, int* y, int* w, bool bUseMon)
265 {
266     int  i, iSel, slen;
267     char buf[STRLEN];
268
269     switch (fitem->edlg)
270     {
271         case edlgBN:
272             AddListItem(list,
273                         CreateButton(x11, fitem->name[0], fitem->bDef, (*ID)++, GroupID, x, (*y), 0, 0, 0));
274             break;
275         case edlgRB:
276             std::strcpy(buf, fitem->def);
277             iSel = -1;
278             for (i = 0; (i < fitem->nname); i++)
279             {
280                 char buf2[100];
281
282                 std::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(
294                                     x11, fitem->name[i], (iSel == i), (*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, fitem->set, fitem->get, fitem->help);
298             }
299             break;
300         case edlgCB:
301         {
302             bool bCheck;
303
304             bCheck = gmx_strcasecmp(fitem->def, "TRUE") == 0;
305             AddListItem(list,
306                         CreateCheckBox(x11, fitem->name[0], bCheck, (*ID)++, GroupID, x, (*y), 0, 0, 0));
307             break;
308         }
309         case edlgST:
310             AddListItem(list,
311                         CreateStaticText(
312                                 x11, fitem->nname, fitem->name, (*ID)++, GroupID, x, (*y), 0, 0, 0));
313             break;
314         case edlgET:
315             slen = std::strlen(fitem->name[0]) + strlen(fitem->def);
316             AddListItem(list,
317                         CreateEditText(
318                                 x11, fitem->name[0], slen, fitem->def, (*ID)++, GroupID, x, (*y), 0, 0, 0));
319             break;
320         case edlgPM:
321         case edlgGB:
322         default: gmx_fatal(FARGS, "Invalid list->list type: %d\n", fitem->edlg);
323     }
324     SetDlgitemOpts(list->list[list->nitem - 1], bUseMon, fitem->set, fitem->get, fitem->help);
325
326     if (fitem->edlg != edlgRB)
327     {
328         (*y) += list->list[list->nitem - 1]->win.height + OFFS_Y;
329         (*w) = std::max((*w), list->list[list->nitem - 1]->win.width);
330     }
331 }
332
333 static void AddListFGroup(t_x11* x11, t_dlgitemlist** grid, t_fgroup* fgroup, t_id* ID, bool bUseMon)
334 {
335     int            i;
336     t_id           GroupID, *ids;
337     t_dlgitemlist* item;
338     int            x, y, w;
339
340     GroupID = (*ID)++;
341     item    = &(grid[fgroup->x][fgroup->y]);
342     AddListItem(item, CreateGroupBox(x11, fgroup->name, GroupID, 0, nullptr, 0, 0, 0, 0, 0));
343     x = 2 * OFFS_X;
344     y = item->list[0]->win.y + item->list[0]->win.height;
345     w = 0;
346     for (i = 0; (i < fgroup->nfitem); i++)
347     {
348         AddListFItem(x11, item, fgroup->fitem[i], GroupID, ID, x, &y, &w, bUseMon);
349     }
350
351     w = std::max(w, item->list[0]->win.width + 4 * OFFS_X);
352     sfree(item->list[0]->u.groupbox.item);
353     sfree(item->list[0]->win.text);
354     snew(ids, item->nitem);
355     for (i = 0; (i < item->nitem - 1); i++)
356     {
357         ids[i] = GroupID + i + 1;
358     }
359     item->list[0] = CreateGroupBox(
360             x11, fgroup->name, GroupID, item->nitem - 1, ids, 2 * OFFS_X, 2 * OFFS_Y, w + 2 * OFFS_X, y, 0);
361     sfree(ids);
362     item->w = fgroup->w;
363     item->h = fgroup->h;
364 }
365
366 static void AddListFSimple(t_x11* x11, t_dlgitemlist** grid, t_fsimple* fsimple, t_id* ID, bool bUseMon)
367 {
368     t_dlgitemlist* item;
369     int            x, y, w;
370
371     item = &(grid[fsimple->x][fsimple->y]);
372     x    = 0;
373     y    = 0;
374     w    = 0;
375     AddListFItem(x11, item, fsimple->fitem, *ID, ID, x, &y, &w, bUseMon);
376     item->w = fsimple->w;
377     item->h = fsimple->h;
378 }
379
380 t_dlg* ReadDlg(t_x11*       x11,
381                Window       Parent,
382                const char*  title,
383                const char*  infile,
384                int          x0,
385                int          y0,
386                bool         bAutoPosition,
387                bool         bUseMon,
388                DlgCallback* cb,
389                void*        data)
390 {
391     t_fgrid*        fgrid;
392     t_dlgitemlist** grid;
393     t_dlg*          dlg;
394     int             i;
395     t_id            ID;
396
397     fgrid = FGridFromFile(infile);
398     dlg   = CreateDlg(x11, Parent, title, x0, y0, 0, 0, 0, cb, data);
399     grid  = NewDlgitemList(fgrid->w, fgrid->h);
400     ID    = 0;
401
402     for (i = 0; (i < fgrid->nfgroup); i++)
403     {
404         AddListFGroup(x11, grid, fgrid->fgroup[i], &ID, bUseMon);
405     }
406     for (i = 0; (i < fgrid->nfsimple); i++)
407     {
408         AddListFSimple(x11, grid, fgrid->fsimple[i], &ID, bUseMon);
409     }
410     AddDlgItemGroups(dlg, fgrid->w, fgrid->h, grid, bAutoPosition);
411
412     DoneFGrid(fgrid);
413
414     return dlg;
415 }