Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / ngmx / popup.c
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-2004, The GROMACS development team,
6  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012, by the GROMACS development team, led by
8  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9  * others, as listed in the AUTHORS file in the top-level source
10  * directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <string.h>
43 #include <math.h>
44 #include <macros.h>
45 #include <smalloc.h>
46 #include <x11.h>
47 #include <xutil.h>
48 #include "popup.h"
49
50 gmx_bool ChildCallBack(t_x11 *x11,XEvent *event, Window w, void *data)
51 {
52   t_child   *child;
53   t_mentry  *m;
54   t_windata *wd;
55   XEvent    letter;
56
57   child=(t_child *)data;
58   m=child->m;
59   wd=&(child->wd);
60   switch (event->type) {
61   case Expose:
62     XSetForeground(x11->disp,x11->gc,x11->fg);
63     TextInRect(x11,w,m->str,16,0,wd->width-16-2,wd->height-2,
64                eXLeft,eYCenter);
65     if (m->bChecked) {
66       int y=x11->font->ascent;
67       XDrawLine(x11->disp,w,x11->gc,2,(y*2)/3,6,y);
68       XDrawLine(x11->disp,w,x11->gc,3,(y*2)/3,7,y);
69       XDrawLine(x11->disp,w,x11->gc,7,y,12,2);
70     }
71     break;
72   case EnterNotify:
73     LightBorder(x11->disp,w,x11->fg);
74     break;
75   case LeaveNotify:
76     LightBorder(x11->disp,w,x11->bg);
77     break;
78   case ButtonRelease:
79     letter.type=ClientMessage;
80     letter.xclient.display=x11->disp;
81     letter.xclient.window=m->send_to ? m->send_to : child->Parent;
82     letter.xclient.message_type=0;
83     letter.xclient.format=32;
84     letter.xclient.data.l[0]=m->nreturn;
85     XSendEvent(x11->disp,letter.xclient.window,True,0,&letter);
86     break;
87   default:
88     break;
89   }
90   return FALSE;
91 }
92
93 gmx_bool MenuCallBack(t_x11 *x11,XEvent *event, Window w, void *data)
94 {
95   t_menu *m;
96
97   m=(t_menu *)data;
98   switch(event->type) {
99   case Expose:
100     /* Nothing to be done */
101     if (m->bGrabbed)
102       m->bGrabbed=
103         GrabOK(stderr,XGrabPointer(x11->disp,m->wd.self,True,
104                                    ButtonReleaseMask,GrabModeAsync,
105                                    GrabModeAsync,m->wd.self,None,CurrentTime));
106     break;
107   case ButtonRelease:
108     hide_menu(x11,m);
109     break;
110   case ClientMessage:
111     event->xclient.window=m->Parent;
112     XSendEvent(x11->disp,m->Parent,True,0,event);
113     break;
114   default:
115     break;
116   }
117   return FALSE;
118 }
119
120 t_menu *init_menu(t_x11 *x11,Window Parent,unsigned long fg,unsigned long bg,
121                   int nent,t_mentry ent[],int ncol)
122 {
123   int       i,mlen,mht,area,ht;
124   int       j,k,l;
125   int       frows,fcol;
126   t_menu    *m;
127   t_child   *kid;
128   t_windata *w;
129
130   snew(m,1);
131   m->nitem=nent;
132   m->Parent=Parent;
133
134   /* Calculate dimensions of the menu */
135   mlen=0;
136   for(i=0; (i<nent); i++)
137     mlen=max(mlen,XTextWidth(x11->font,ent[i].str,strlen(ent[i].str)));
138   mht=XTextHeight(x11->font);
139   /* Now we have the biggest single box, add a border of 2 pixels */
140   mlen+=20; /* We need extra space at the left for checkmarks */
141   mht+=4;
142   /* Calculate the area of the menu */
143   area=mlen*mht;
144   ht=sqrt(area);
145   /* No the number of rows per column, only beyond 8 rows */
146   if (ncol == 0) {
147     if (nent > 8)
148       frows=(1+ht/mht);
149     else
150       frows=nent;
151     fcol=nent/frows;
152   }
153   else {
154     fcol=ncol;
155     frows=nent/ncol;
156     if (nent % ncol)
157       frows++;
158   }
159   InitWin(&(m->wd),10,10,fcol*mlen,frows*mht,1,"Menu");
160   snew(m->item,nent);
161   m->wd.self=XCreateSimpleWindow(x11->disp,Parent,
162                                  m->wd.x, m->wd.y,
163                                  m->wd.width,m->wd.height,
164                                  m->wd.bwidth,fg,bg);
165   x11->RegisterCallback(x11,m->wd.self,Parent,MenuCallBack,m);
166   x11->SetInputMask(x11,m->wd.self,ExposureMask | 
167                     OwnerGrabButtonMask | ButtonReleaseMask);
168
169   for(j=l=0; (j<fcol); j++)
170     for(k=0; (k<frows) && (l<nent); k++,l++) {
171       kid=&(m->item[l]);
172       kid->m=&(ent[l]);
173       kid->Parent=Parent; 
174       w=&(kid->wd);
175       InitWin(w,j*mlen,k*mht,mlen-2,mht-2,1,NULL);
176       w->self=XCreateSimpleWindow(x11->disp,m->wd.self,
177                                   w->x,w->y,w->width,w->height,
178                                   w->bwidth,bg,bg);
179       x11->RegisterCallback(x11,w->self,m->wd.self,
180                             ChildCallBack,kid);
181       x11->SetInputMask(x11,w->self,
182                         ButtonPressMask | ButtonReleaseMask | 
183                         OwnerGrabButtonMask | ExposureMask | 
184                         EnterWindowMask | LeaveWindowMask);
185     }
186
187   return m;
188 }
189
190 void show_menu(t_x11 *x11,t_menu *m,int x,int y,gmx_bool bGrab)
191 {
192   XMoveWindow(x11->disp,m->wd.self,x,y);
193   m->bGrabbed=bGrab;
194   XMapWindow(x11->disp,m->wd.self);
195   XMapSubwindows(x11->disp,m->wd.self);
196 }
197
198 void hide_menu(t_x11 *x11,t_menu *m)
199 {
200   if (m->bGrabbed)
201     XUngrabPointer(x11->disp,CurrentTime);
202   XUnmapWindow(x11->disp,m->wd.self);
203 }
204
205 void check_menu_item(t_menu *m,int nreturn,gmx_bool bStatus)
206 {
207   int i;
208
209   for(i=0; (i<m->nitem); i++)
210     if(m->item[i].m->nreturn==nreturn)
211       m->item[i].m->bChecked=bStatus;
212 }
213
214 void done_menu(t_x11 *x11,t_menu *m)
215 {
216   int i;
217
218   for(i=0; (i<m->nitem); i++)
219     x11->UnRegisterCallback(x11,m->item[i].wd.self);
220   sfree(m->item);
221   x11->UnRegisterCallback(x11,m->wd.self);
222   sfree(m);
223 }
224
225 int menu_width(t_menu *m)
226 {
227   return m->wd.width;
228 }
229
230 int menu_height(t_menu *m)
231 {
232   return m->wd.height;
233 }
234