Merge "Merge branch release-4-6"
[alexxy/gromacs.git] / src / programs / view / view.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-2004, 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 <stdio.h>
40 #include <ctype.h>
41 #include <string.h>
42 #include "sysstuff.h"
43 #include "macros.h"
44 #include "smalloc.h"
45 #include "gmx_fatal.h"
46 #include "typedefs.h"
47 #include "string2.h"
48 #include "statutil.h"
49 #include "copyrite.h"
50 #include "gromacs/fileio/confio.h"
51 #include "gromacs/fileio/tpxio.h"
52
53 #ifdef GMX_X11
54
55 #include "Xstuff.h"
56 #include "gromacs.bm"
57 #include "xutil.h"
58 #include "dialogs.h"
59 #include "writeps.h"
60 #include "molps.h"
61 #include "nmol.h"
62
63 static void dump_it(t_manager *man)
64 {
65     t_psdata ps;
66
67     ps = ps_open("view.ps", 0, 0, man->molw->wd.width, man->molw->wd.height);
68     ps_draw_mol(ps, man);
69     ps_close(ps);
70 }
71
72 static void done_gmx(t_x11 *x11, t_gmx *gmx)
73 {
74     done_logo(x11, gmx->logo);
75     done_pd(x11, gmx->pd);
76     done_man(x11, gmx->man);
77     done_dlgs(gmx);
78     x11->UnRegisterCallback(x11, gmx->wd->self);
79 }
80
81 static void move_gmx(t_x11 *x11, t_gmx *gmx, int width, int height,
82                      bool bSizePD)
83 {
84     int y0, wl, hl;
85 #ifdef DEBUG
86     fprintf(stderr, "Move gmx %dx%d\n", width, height);
87 #endif
88     y0 = XTextHeight(x11->font);
89     /* Resize PD-Menu */
90     if (bSizePD)
91     {
92         XResizeWindow(x11->disp, gmx->pd->wd.self, width, y0);
93     }
94
95     XMoveWindow(x11->disp, gmx->man->wd.self, 0, y0+1);
96     XResizeWindow(x11->disp, gmx->man->wd.self, width, height-y0-1);
97
98     wl = gmx->logo->wd.width;
99     hl = gmx->logo->wd.height;
100     XMoveWindow(x11->disp, gmx->logo->wd.self, (width-wl)/2, (height-y0-hl)/2);
101 }
102
103 static bool HandleClient(t_x11 *x11, int ID, t_gmx *gmx)
104 {
105     t_pulldown *pd;
106
107     pd = gmx->pd;
108
109     switch (ID)
110     {
111         /* File Menu */
112         case IDDUMPWIN:
113             write_gmx(x11, gmx, IDDODUMP);
114             break;
115         case IDDODUMP:
116             if (gmx->man->bAnimate)
117             {
118                 hide_but(x11, gmx->man->vbox);
119             }
120             dump_it(gmx->man);
121             if (gmx->man->bAnimate)
122             {
123                 show_but(x11, gmx->man->vbox);
124             }
125             break;
126         case IDCLOSE:
127         case IDIMPORT:
128         case IDEXPORT:
129             ShowDlg(gmx->dlgs[edExport]);
130             break;
131         case IDDOEXPORT:
132             write_sto_conf(gmx->confout, *gmx->man->top.name,
133                            &(gmx->man->top.atoms),
134                            gmx->man->x, NULL, gmx->man->molw->ePBC, gmx->man->box);
135             break;
136         case IDQUIT:
137             show_mb(gmx, emQuit);
138             break;
139         case IDTERM:
140             done_gmx(x11, gmx);
141             return true;
142
143         /* Edit Menu */
144         case IDEDITTOP:
145             edit_file("topol.gmx");
146             break;
147         case IDEDITCOORDS:
148             edit_file("confin.gmx");
149             break;
150         case IDEDITPARAMS:
151             edit_file("mdparin.gmx");
152             break;
153
154         /* Display Menu */
155         case IDFILTER:
156             if (gmx->filter)
157             {
158                 ShowDlg(gmx->dlgs[edFilter]);
159             }
160             break;
161         case IDDOFILTER:
162             do_filter(x11, gmx->man, gmx->filter);
163             break;
164         case IDANIMATE:
165             check_pd_item(pd, IDANIMATE, toggle_animate(x11, gmx->man));
166             break;
167         case IDLABELSOFF:
168             no_labels(x11, gmx->man);
169             break;
170         case IDRESETVIEW:
171             reset_view(gmx->man->view);
172             ExposeWin(x11->disp, gmx->man->molw->wd.self);
173             break;
174         case IDPHOTO:
175             show_mb(gmx, emNotImplemented);
176             break;
177         case IDBONDOPTS:
178             ShowDlg(gmx->dlgs[edBonds]);
179             break;
180         case IDTHIN:
181             set_bond_type(x11, gmx->man->molw, eBThin);
182             break;
183         case IDFAT:
184             set_bond_type(x11, gmx->man->molw, eBFat);
185             break;
186         case IDVERYFAT:
187             set_bond_type(x11, gmx->man->molw, eBVeryFat);
188             break;
189         case IDBALLS:
190             set_bond_type(x11, gmx->man->molw, eBSpheres);
191             break;
192         case IDNOBOX:
193             set_box_type(x11, gmx->man->molw, esbNone);
194             break;
195         case IDRECTBOX:
196             set_box_type(x11, gmx->man->molw, esbRect);
197             break;
198         case IDTRIBOX:
199             set_box_type(x11, gmx->man->molw, esbTri);
200             break;
201         case IDTOBOX:
202             set_box_type(x11, gmx->man->molw, esbTrunc);
203             break;
204
205         /* Analysis Menu */
206         case IDBOND:
207         case IDANGLE:
208         case IDDIH:
209         case IDRMS:
210         case IDRDF:
211         case IDENERGIES:
212         case IDCORR:
213             show_mb(gmx, emNotImplemented);
214             break;
215
216         /* Help Menu */
217         case IDHELP:
218             show_mb(gmx, emHelp);
219             break;
220         case IDABOUT:
221             show_logo(x11, gmx->logo);
222             break;
223
224         default:
225             break;
226     }
227     return false;
228 }
229
230 static bool MainCallBack(t_x11 *x11, XEvent *event, Window w, void *data)
231 {
232     t_gmx    *gmx;
233     int       nsel, width, height;
234     bool      result;
235
236     result = false;
237     gmx    = (t_gmx *)data;
238     switch (event->type)
239     {
240         case ButtonRelease:
241             hide_pd(x11, gmx->pd);
242             break;
243         case ConfigureNotify:
244             width  = event->xconfigure.width;
245             height = event->xconfigure.height;
246             if ((width != gmx->wd->width) || (height != gmx->wd->height))
247             {
248                 move_gmx(x11, gmx, width, height, true);
249             }
250             break;
251         case ClientMessage:
252             hide_pd(x11, gmx->pd);
253             nsel   = event->xclient.data.l[0];
254             result = HandleClient(x11, nsel, gmx);
255             break;
256         default:
257             break;
258     }
259     return result;
260 }
261
262 static t_mentry  FileMenu[] = {
263     { 0,  IDEXPORT,   false,  "Export..." },
264     { 0,  IDDUMPWIN,  false,  "Print"     },
265     { 0,  IDQUIT,     false,  "Quit"      }
266 };
267
268 static t_mentry  DispMenu[] = {
269     { 0,  IDFILTER,   false,  "Filter..." },
270     { 0,  IDANIMATE,  false,  "Animate"   },
271     { 0,  IDLABELSOFF,    false,  "Labels Off"},
272     { 0,  IDRESETVIEW,    false,  "Reset View"},
273     { 0,  IDBONDOPTS,     false,  "Options..."}
274 };
275
276 static t_mentry  HelpMenu[] = {
277     { 0,  IDHELP,     false,  "Help"             },
278     { 0,  IDABOUT,    false,  "About Gromacs..." }
279 };
280
281 static t_mentry *gmx_pd[] = { FileMenu, DispMenu, HelpMenu };
282
283 #define MSIZE asize(gmx_pd)
284
285 static int         gmx_pd_size[MSIZE] = {
286     asize(FileMenu), asize(DispMenu), asize(HelpMenu)
287 };
288
289 static const char *MenuTitle[MSIZE] = {
290     "File", "Display", "Help"
291 };
292
293 static void init_gmx(t_x11 *x11, char *program, int nfile, t_filenm fnm[],
294                      const output_env_t oenv)
295 {
296     Pixmap                pm;
297     t_gmx                *gmx;
298     XSizeHints            hints;
299     int                   w0, h0;
300     int                   natom, natom_trx;
301     t_topology            top;
302     int                   ePBC;
303     matrix                box;
304     t_trxframe            fr;
305     t_trxstatus          *status;
306     char                  quote[256];
307
308     snew(gmx, 1);
309     snew(gmx->wd, 1);
310
311     ePBC = read_tpx_top(ftp2fn(efTPX, nfile, fnm),
312                         NULL, box, &natom, NULL, NULL, NULL, &top);
313
314     read_first_frame(oenv, &status, ftp2fn(efTRX, nfile, fnm), &fr, TRX_DONT_SKIP);
315     close_trx(status);
316     natom_trx = fr.natoms;
317
318     /* Creates a simple window */
319     w0 = DisplayWidth(x11->disp, x11->screen)-132;
320     h0 = DisplayHeight(x11->disp, x11->screen)-140;
321     bromacs(quote, 255);
322     InitWin(gmx->wd, 0, 0, w0, h0, 3, quote);
323     gmx->wd->self = XCreateSimpleWindow(x11->disp, x11->root,
324                                         gmx->wd->x, gmx->wd->y,
325                                         gmx->wd->width, gmx->wd->height,
326                                         gmx->wd->bwidth, WHITE, BLACK);
327     pm = XCreatePixmapFromBitmapData(x11->disp, x11->root,
328                                      (char *)gromacs_bits, gromacs_width,
329                                      gromacs_height,
330                                      WHITE, BLACK, 1);
331     hints.flags      = PMinSize;
332     hints.min_width  = 2*EWIDTH+40;
333     hints.min_height = EHEIGHT+LDHEIGHT+LEGHEIGHT+40;
334     XSetStandardProperties(x11->disp, gmx->wd->self, gmx->wd->text, program,
335                            pm, NULL, 0, &hints);
336
337     x11->RegisterCallback(x11, gmx->wd->self, x11->root, MainCallBack, gmx);
338     x11->SetInputMask(x11, gmx->wd->self,
339                       ButtonPressMask     | ButtonReleaseMask |
340                       OwnerGrabButtonMask | ExposureMask      |
341                       StructureNotifyMask);
342
343     /* The order of creating windows is important here! */
344     /* Manager */
345     gmx->man  = init_man(x11, gmx->wd->self, 0, 0, 1, 1, WHITE, BLACK, ePBC, box, oenv);
346     gmx->logo = init_logo(x11, gmx->wd->self, false);
347
348     /* Now put all windows in the proper place */
349     move_gmx(x11, gmx, w0, h0, false);
350
351     XMapWindow(x11->disp, gmx->wd->self);
352     map_man(x11, gmx->man);
353
354     /* Pull Down menu */
355     gmx->pd = init_pd(x11, gmx->wd->self, gmx->wd->width,
356                       x11->fg, x11->bg,
357                       MSIZE, gmx_pd_size, gmx_pd, MenuTitle);
358
359     /* Dialogs & Filters */
360
361     gmx->filter = init_filter(&(top.atoms), ftp2fn_null(efNDX, nfile, fnm),
362                               natom_trx);
363
364     init_dlgs(x11, gmx);
365
366     /* Now do file shit */
367     set_file(x11, gmx->man, ftp2fn(efTRX, nfile, fnm), ftp2fn(efTPX, nfile, fnm));
368
369     ShowDlg(gmx->dlgs[edFilter]);
370 }
371 #endif
372
373 int gmx_view(int argc, char *argv[])
374 {
375     const char  *desc[] = {
376         "[TT]view[tt] is the GROMACS trajectory viewer. This program reads a",
377         "trajectory file, a run input file and an index file and plots a",
378         "3D structure of your molecule on your standard X Window",
379         "screen. No need for a high end graphics workstation, it even",
380         "works on Monochrome screens.[PAR]",
381         "The following features have been implemented:",
382         "3D view, rotation, translation and scaling of your molecule(s),",
383         "labels on atoms, animation of trajectories,",
384         "hardcopy in PostScript format, user defined atom-filters",
385         "runs on MIT-X (real X), open windows and motif,",
386         "user friendly menus, option to remove periodicity, option to",
387         "show computational box.[PAR]",
388         "Some of the more common X command line options can be used: ",
389         "[TT]-bg[tt], [TT]-fg[tt] change colors, [TT]-font fontname[tt] changes the font."
390     };
391     const char  *bugs[] = {
392         "Balls option does not work",
393         "Some times dumps core without a good reason"
394     };
395
396     output_env_t oenv;
397     t_filenm     fnm[] = {
398         { efTRX, "-f", NULL, ffREAD },
399         { efTPX, NULL, NULL, ffREAD },
400         { efNDX, NULL, NULL, ffOPTRD }
401     };
402 #define NFILE asize(fnm)
403
404     if (parse_common_args(&argc, argv, PCA_CAN_TIME, NFILE, fnm,
405                           0, NULL, asize(desc), desc, asize(bugs), bugs, &oenv))
406     {
407 #ifndef GMX_X11
408         fprintf(stderr, "Compiled without X-Windows - can not run viewer.\n");
409 #else
410         t_x11 *x11;
411
412         if ((x11 = GetX11(&argc, argv)) == NULL)
413         {
414             fprintf(stderr, "Can't connect to X Server.\n"
415                     "Check your DISPLAY environment variable\n");
416         }
417         else
418         {
419             init_gmx(x11, argv[0], NFILE, fnm, oenv);
420             x11->MainLoop(x11);
421             x11->CleanUp(x11);
422         }
423 #endif
424     }
425     return 0;
426 }