Merge release-4-6 into release-5-0
[alexxy/gromacs.git] / src / programs / view / dialogs.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 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h> // for fork()
43 #endif
44
45 #include "gromacs/utility/smalloc.h"
46 #include "sysstuff.h"
47 #include "macros.h"
48 #include "gromacs/utility/cstringutil.h"
49 #include "x11.h"
50 #include "xdlghi.h"
51 #include "xmb.h"
52 #include "dialogs.h"
53 #include "names.h"
54 #include "nmol.h"
55 #include "manager.h"
56 #include "gromacs/fileio/futil.h"
57 #include "gmx_fatal.h"
58
59 #define MBFLAGS /* MB_APPLMODAL | */ MB_DONTSHOW
60
61 void write_gmx(t_x11 *x11, t_gmx *gmx, int mess)
62 {
63     XEvent letter;
64
65     letter.type                 = ClientMessage;
66     letter.xclient.display      = x11->disp;
67     letter.xclient.window       = gmx->wd->self;
68     letter.xclient.message_type = 0;
69     letter.xclient.format       = 32;
70     letter.xclient.data.l[0]    = mess;
71     letter.xclient.data.l[1]    = Button1;
72     XSendEvent(x11->disp, letter.xclient.window, True, 0, &letter);
73 }
74
75 static void shell_comm(const char *title, const char *script, int nsleep)
76 {
77     FILE *tfil;
78     char  command[STRLEN];
79     char  tmp[32];
80
81     strcpy(tmp, "dialogXXXXXX");
82     gmx_tmpnam(tmp);
83
84     if ((tfil = fopen(tmp, "w")) == NULL)
85     {
86         sprintf(tmp, "%ctmp%cdialogXXXXXX", DIR_SEPARATOR, DIR_SEPARATOR);
87         gmx_tmpnam(tmp);
88     }
89     else
90     {
91         fclose(tfil);
92     }
93     if ((tfil = fopen(tmp, "w")) == NULL)
94     {
95         gmx_fatal(FARGS, "Can not open tmp file %s", tmp);
96     }
97
98     fprintf(tfil, "%s\n", script);
99     fprintf(tfil, "sleep %d\n", nsleep);
100     fclose(tfil);
101
102     sprintf(command, "xterm -title %s -e sh %s", title, tmp);
103 #ifdef DEBUG
104     fprintf(stderr, "command: %s\n", command);
105 #endif
106
107 #ifdef GMX_NO_SYSTEM
108     printf("Warning-- No calls to system(3) supported on this platform.");
109     printf("Warning-- Skipping execution of 'system(\"%s\")'.", buf);
110 #else
111     if (0 != system(command))
112     {
113         gmx_fatal(FARGS, "Failed to execute command: %s", command);
114     }
115 #endif
116
117 #ifdef DEBUG
118     unlink(tmp)
119 #endif
120 }
121
122 void show_mb(t_gmx *gmx, int mb)
123 {
124     if (mb >= 0 && mb < emNR)
125     {
126         gmx->which_mb = mb;
127         ShowDlg(gmx->mboxes[mb]);
128     }
129 }
130
131 static void hide_mb(t_gmx *gmx)
132 {
133     if (gmx->which_mb >= 0 && gmx->which_mb < emNR)
134     {
135         HideDlg(gmx->mboxes[gmx->which_mb]);
136         gmx->which_mb = -1;
137     }
138 }
139
140 static void MBCallback(t_x11 * /*x11*/, int dlg_mess, int /*item_id*/,
141                        char * /*set*/, void *data)
142 {
143     t_gmx *gmx;
144
145     gmx = (t_gmx *)data;
146     if (dlg_mess == DLG_EXIT)
147     {
148         hide_mb(gmx);
149     }
150 }
151
152 static t_dlg *about_mb(t_x11 *x11, t_gmx *gmx)
153 {
154     const char *lines[] = {
155         "         G R O M A C S",
156         " Machine for Simulating Chemistry",
157         "       Copyright (c) 1992-2013",
158         "  Berk Hess, David van der Spoel, Erik Lindahl",
159         "        and many collaborators!"
160     };
161
162     return MessageBox(x11, gmx->wd->self, gmx->wd->text,
163                       asize(lines), lines, MB_OK | MB_ICONGMX | MBFLAGS,
164                       MBCallback, gmx);
165 }
166
167 static void QuitCB(t_x11 *x11, int dlg_mess, int /*item_id*/,
168                    char *set, void *data)
169 {
170     t_gmx  *gmx;
171     gmx = (t_gmx *)data;
172
173     hide_mb(gmx);
174     if (dlg_mess == DLG_EXIT)
175     {
176         if (gmx_strcasecmp("yes", set) == 0)
177         {
178             write_gmx(x11, gmx, IDTERM);
179         }
180     }
181 }
182
183 static t_dlg *quit_mb(t_x11 *x11, t_gmx *gmx)
184 {
185     const char *lines[] = {
186         " Do you really want to Quit ?"
187     };
188
189     return MessageBox(x11, gmx->wd->self, gmx->wd->text,
190                       asize(lines), lines,
191                       MB_YESNO | MB_ICONSTOP | MBFLAGS,
192                       QuitCB, gmx);
193 }
194
195 static t_dlg *help_mb(t_x11 *x11, t_gmx *gmx)
196 {
197     const char *lines[] = {
198         " Help will soon be added"
199     };
200
201     return MessageBox(x11, gmx->wd->self, gmx->wd->text,
202                       asize(lines), lines,
203                       MB_OK | MB_ICONINFORMATION | MBFLAGS,
204                       MBCallback, gmx);
205 }
206
207 static t_dlg *ni_mb(t_x11 *x11, t_gmx *gmx)
208 {
209     const char *lines[] = {
210         " This feature has not been",
211         " implemented yet."
212     };
213
214     return MessageBox(x11, gmx->wd->self, gmx->wd->text,
215                       asize(lines), lines,
216                       MB_OK | MB_ICONEXCLAMATION | MBFLAGS,
217                       MBCallback, gmx);
218 }
219
220 enum {
221     eExE, eExGrom, eExPdb, eExConf, eExNR
222 };
223
224 static void ExportCB(t_x11 *x11, int dlg_mess, int item_id,
225                      char *set, void *data)
226 {
227     bool       bOk;
228     t_gmx     *gmx;
229     t_dlg     *dlg;
230
231     gmx = (t_gmx *)data;
232     dlg = gmx->dlgs[edExport];
233     switch (dlg_mess)
234     {
235         case DLG_SET:
236             switch (item_id)
237             {
238                 case eExGrom:
239                     gmx->ExpMode = eExpGromos;
240                     break;
241                 case eExPdb:
242                     gmx->ExpMode = eExpPDB;
243                     break;
244                 default:
245                     break;
246             }
247 #ifdef DEBUG
248             fprintf(stderr, "exportcb: item_id=%d\n", item_id);
249 #endif
250             break;
251         case DLG_EXIT:
252             if ((bOk = gmx_strcasecmp("ok", set)) == 0)
253             {
254                 strcpy(gmx->confout, EditText(dlg, eExConf));
255             }
256             HideDlg(dlg);
257             if (bOk)
258             {
259                 write_gmx(x11, gmx, IDDOEXPORT);
260             }
261             break;
262     }
263 }
264
265 enum {
266     eg0, egTOPOL, egCONFIN, egPARAM, eg1, eg1PROC, eg32PROC
267 };
268
269 static void Extract(t_dlg *dlg, int ID, char *buf)
270 {
271     char *et;
272
273     et = EditText(dlg, ID);
274     if (et)
275     {
276         strcpy(buf, et);
277     }
278 }
279
280 enum bond_set {
281     ebShowH = 11, ebDPlus, ebRMPBC, ebCue, ebSkip, ebWait
282 };
283
284 static void BondsCB(t_x11 *x11, int dlg_mess, int item_id,
285                     char *set, void *data)
286 {
287     static int ebond = -1;
288     static int ebox  = -1;
289     bool       bOk, bBond = false;
290     int        nskip, nwait;
291     t_gmx     *gmx;
292     char      *endptr;
293
294     gmx = (t_gmx *)data;
295     if (ebond == -1)
296     {
297         ebond = gmx->man->molw->bond_type;
298         ebox  = gmx->man->molw->boxtype;
299     }
300     switch (dlg_mess)
301     {
302         case DLG_SET:
303             if (item_id <= eBNR)
304             {
305                 ebond = item_id-1;
306                 bBond = false;
307             }
308             else if (item_id <= eBNR+esbNR+1)
309             {
310                 ebox  = item_id-eBNR-2;
311                 bBond = true;
312             }
313             else
314             {
315
316 #define DO_NOT(b) (b) = (!(b))
317
318                 switch (item_id)
319                 {
320                     case ebShowH:
321                         toggle_hydrogen(x11, gmx->man->molw);
322                         break;
323                     case ebDPlus:
324                         DO_NOT(gmx->man->bPlus);
325 #ifdef DEBUG
326                         fprintf(stderr, "gmx->man->bPlus=%s\n",
327                                 gmx->man->bPlus ? "true" : "false");
328 #endif
329                         break;
330                     case ebRMPBC:
331                         toggle_pbc(gmx->man);
332                         break;
333                     case ebCue:
334                         DO_NOT(gmx->man->bSort);
335 #ifdef DEBUG
336                         fprintf(stderr, "gmx->man->bSort=%s\n",
337                                 gmx->man->bSort ? "true" : "false");
338 #endif
339                         break;
340                     case ebSkip:
341                         nskip = strtol(set, &endptr, 10);
342                         if (endptr != set)
343                         {
344 #ifdef DEBUG
345                             fprintf(stderr, "nskip: %d frames\n", nskip);
346 #endif
347                             if (nskip >= 0)
348                             {
349                                 gmx->man->nSkip = nskip;
350                             }
351                         }
352                         break;
353                     case ebWait:
354                         nwait = strtol(set, &endptr, 10);
355                         if (endptr != set)
356                         {
357 #ifdef DEBUG
358                             fprintf(stderr, "wait: %d ms\n", nwait);
359 #endif
360                             if (nwait >= 0)
361                             {
362                                 gmx->man->nWait = nwait;
363                             }
364                         }
365                     default:
366 #ifdef DEBUG
367                         fprintf(stderr, "item_id: %d, set: %s\n", item_id, set);
368 #endif
369                         break;
370                 }
371             }
372             break;
373         case DLG_EXIT:
374             bOk = (gmx_strcasecmp("ok", set) == 0);
375             HideDlg(gmx->dlgs[edBonds]);
376             if (bOk)
377             {
378                 if (bBond)
379                 {
380                     switch (ebond)
381                     {
382                         case eBThin:
383                             write_gmx(x11, gmx, IDTHIN);
384                             break;
385                         case eBFat:
386                             write_gmx(x11, gmx, IDFAT);
387                             break;
388                         case eBVeryFat:
389                             write_gmx(x11, gmx, IDVERYFAT);
390                             break;
391                         case eBSpheres:
392                             write_gmx(x11, gmx, IDBALLS);
393                             break;
394                         default:
395                             gmx_fatal(FARGS, "Invalid bond type %d at %s, %d",
396                                       ebond, __FILE__, __LINE__);
397                     }
398                 }
399                 else
400                 {
401                     switch (ebox)
402                     {
403                         case esbNone:
404                             write_gmx(x11, gmx, IDNOBOX);
405                             break;
406                         case esbRect:
407                             write_gmx(x11, gmx, IDRECTBOX);
408                             break;
409                         case esbTri:
410                             write_gmx(x11, gmx, IDTRIBOX);
411                             break;
412                         case esbTrunc:
413                             write_gmx(x11, gmx, IDTOBOX);
414                             break;
415                         default:
416                             gmx_fatal(FARGS, "Invalid box type %d at %s, %d",
417                                       ebox, __FILE__, __LINE__);
418                     }
419                 }
420             }
421             break;
422     }
423 }
424
425 enum {
426     esFUNCT = 1, esBSHOW, esINFIL, esINDEXFIL, esLSQ, esSHOW, esPLOTFIL
427 };
428
429 static bool in_set(int i, int n, int set[])
430 {
431     int j;
432     for (j = 0; (j < n); j++)
433     {
434         if (set[j] == i)
435         {
436             return true;
437         }
438     }
439     return false;
440 }
441
442 typedef t_dlg *t_mmb (t_x11 *x11, t_gmx *gmx);
443
444 typedef struct {
445     const char  *dlgfile;
446     DlgCallback *cb;
447 } t_dlginit;
448
449 void init_dlgs(t_x11 *x11, t_gmx *gmx)
450 {
451     static t_dlginit di[] = {
452         { "export.dlg",   ExportCB },
453         { "bonds.dlg",    BondsCB  }
454     };
455     static t_mmb *mi[emNR] = { quit_mb,    help_mb,    about_mb,   ni_mb };
456     unsigned int i;
457
458     snew(gmx->dlgs, edNR);
459     for (i = 0; (i < asize(di)); i++)
460     {
461         gmx->dlgs[i] = ReadDlg(x11, gmx->wd->self, di[i].dlgfile,
462                                di[i].dlgfile,
463                                0, 0, true, false, di[i].cb, gmx);
464     }
465
466     gmx->dlgs[edFilter] = select_filter(x11, gmx);
467
468     snew(gmx->mboxes, emNR);
469     for (i = 0; (i < emNR); i++)
470     {
471         gmx->mboxes[i] = mi[i](x11, gmx);
472     }
473     gmx->which_mb = -1;
474 }
475
476 void done_dlgs(t_gmx *gmx)
477 {
478     int i;
479
480     for (i = 0; (i < edNR); i++)
481     {
482         FreeDlg(gmx->dlgs[i]);
483     }
484     for (i = 0; (i < emNR); i++)
485     {
486         FreeDlg(gmx->mboxes[i]);
487     }
488 }
489
490 void edit_file(const char *fn)
491 {
492     if (fork() == 0)
493     {
494         char script[256];
495
496         sprintf(script, "vi  %s", fn);
497         shell_comm(fn, script, 0);
498         exit(0);
499     }
500 }