9df9fe9440e5cb0432dd990884420ec0f5cdbe1a
[alexxy/gromacs.git] / src / ngmx / popup.c
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 <string.h>
40 #include <math.h>
41 #include <macros.h>
42 #include <smalloc.h>
43 #include <x11.h>
44 #include <xutil.h>
45 #include "popup.h"
46
47 gmx_bool ChildCallBack(t_x11 *x11,XEvent *event, Window w, void *data)
48 {
49   t_child   *child;
50   t_mentry  *m;
51   t_windata *wd;
52   XEvent    letter;
53
54   child=(t_child *)data;
55   m=child->m;
56   wd=&(child->wd);
57   switch (event->type) {
58   case Expose:
59     XSetForeground(x11->disp,x11->gc,x11->fg);
60     TextInRect(x11,w,m->str,16,0,wd->width-16-2,wd->height-2,
61                eXLeft,eYCenter);
62     if (m->bChecked) {
63       int y=x11->font->ascent;
64       XDrawLine(x11->disp,w,x11->gc,2,(y*2)/3,6,y);
65       XDrawLine(x11->disp,w,x11->gc,3,(y*2)/3,7,y);
66       XDrawLine(x11->disp,w,x11->gc,7,y,12,2);
67     }
68     break;
69   case EnterNotify:
70     LightBorder(x11->disp,w,x11->fg);
71     break;
72   case LeaveNotify:
73     LightBorder(x11->disp,w,x11->bg);
74     break;
75   case ButtonRelease:
76     letter.type=ClientMessage;
77     letter.xclient.display=x11->disp;
78     letter.xclient.window=m->send_to ? m->send_to : child->Parent;
79     letter.xclient.message_type=0;
80     letter.xclient.format=32;
81     letter.xclient.data.l[0]=m->nreturn;
82     XSendEvent(x11->disp,letter.xclient.window,True,0,&letter);
83     break;
84   default:
85     break;
86   }
87   return FALSE;
88 }
89
90 gmx_bool MenuCallBack(t_x11 *x11,XEvent *event, Window w, void *data)
91 {
92   t_menu *m;
93
94   m=(t_menu *)data;
95   switch(event->type) {
96   case Expose:
97     /* Nothing to be done */
98     if (m->bGrabbed)
99       m->bGrabbed=
100         GrabOK(stderr,XGrabPointer(x11->disp,m->wd.self,True,
101                                    ButtonReleaseMask,GrabModeAsync,
102                                    GrabModeAsync,m->wd.self,None,CurrentTime));
103     break;
104   case ButtonRelease:
105     hide_menu(x11,m);
106     break;
107   case ClientMessage:
108     event->xclient.window=m->Parent;
109     XSendEvent(x11->disp,m->Parent,True,0,event);
110     break;
111   default:
112     break;
113   }
114   return FALSE;
115 }
116
117 t_menu *init_menu(t_x11 *x11,Window Parent,unsigned long fg,unsigned long bg,
118                   int nent,t_mentry ent[],int ncol)
119 {
120   int       i,mlen,mht,area,ht;
121   int       j,k,l;
122   int       frows,fcol;
123   t_menu    *m;
124   t_child   *kid;
125   t_windata *w;
126
127   snew(m,1);
128   m->nitem=nent;
129   m->Parent=Parent;
130
131   /* Calculate dimensions of the menu */
132   mlen=0;
133   for(i=0; (i<nent); i++)
134     mlen=max(mlen,XTextWidth(x11->font,ent[i].str,strlen(ent[i].str)));
135   mht=XTextHeight(x11->font);
136   /* Now we have the biggest single box, add a border of 2 pixels */
137   mlen+=20; /* We need extra space at the left for checkmarks */
138   mht+=4;
139   /* Calculate the area of the menu */
140   area=mlen*mht;
141   ht=sqrt(area);
142   /* No the number of rows per column, only beyond 8 rows */
143   if (ncol == 0) {
144     if (nent > 8)
145       frows=(1+ht/mht);
146     else
147       frows=nent;
148     fcol=nent/frows;
149   }
150   else {
151     fcol=ncol;
152     frows=nent/ncol;
153     if (nent % ncol)
154       frows++;
155   }
156   InitWin(&(m->wd),10,10,fcol*mlen,frows*mht,1,"Menu");
157   snew(m->item,nent);
158   m->wd.self=XCreateSimpleWindow(x11->disp,Parent,
159                                  m->wd.x, m->wd.y,
160                                  m->wd.width,m->wd.height,
161                                  m->wd.bwidth,fg,bg);
162   x11->RegisterCallback(x11,m->wd.self,Parent,MenuCallBack,m);
163   x11->SetInputMask(x11,m->wd.self,ExposureMask | 
164                     OwnerGrabButtonMask | ButtonReleaseMask);
165
166   for(j=l=0; (j<fcol); j++)
167     for(k=0; (k<frows) && (l<nent); k++,l++) {
168       kid=&(m->item[l]);
169       kid->m=&(ent[l]);
170       kid->Parent=Parent; 
171       w=&(kid->wd);
172       InitWin(w,j*mlen,k*mht,mlen-2,mht-2,1,NULL);
173       w->self=XCreateSimpleWindow(x11->disp,m->wd.self,
174                                   w->x,w->y,w->width,w->height,
175                                   w->bwidth,bg,bg);
176       x11->RegisterCallback(x11,w->self,m->wd.self,
177                             ChildCallBack,kid);
178       x11->SetInputMask(x11,w->self,
179                         ButtonPressMask | ButtonReleaseMask | 
180                         OwnerGrabButtonMask | ExposureMask | 
181                         EnterWindowMask | LeaveWindowMask);
182     }
183
184   return m;
185 }
186
187 void show_menu(t_x11 *x11,t_menu *m,int x,int y,gmx_bool bGrab)
188 {
189   XMoveWindow(x11->disp,m->wd.self,x,y);
190   m->bGrabbed=bGrab;
191   XMapWindow(x11->disp,m->wd.self);
192   XMapSubwindows(x11->disp,m->wd.self);
193 }
194
195 void hide_menu(t_x11 *x11,t_menu *m)
196 {
197   if (m->bGrabbed)
198     XUngrabPointer(x11->disp,CurrentTime);
199   XUnmapWindow(x11->disp,m->wd.self);
200 }
201
202 void check_menu_item(t_menu *m,int nreturn,gmx_bool bStatus)
203 {
204   int i;
205
206   for(i=0; (i<m->nitem); i++)
207     if(m->item[i].m->nreturn==nreturn)
208       m->item[i].m->bChecked=bStatus;
209 }
210
211 void done_menu(t_x11 *x11,t_menu *m)
212 {
213   int i;
214
215   for(i=0; (i<m->nitem); i++)
216     x11->UnRegisterCallback(x11,m->item[i].wd.self);
217   sfree(m->item);
218   x11->UnRegisterCallback(x11,m->wd.self);
219   sfree(m);
220 }
221
222 int menu_width(t_menu *m)
223 {
224   return m->wd.width;
225 }
226
227 int menu_height(t_menu *m)
228 {
229   return m->wd.height;
230 }
231