10c1bb8dd65615b9ac1e17313e2d4f901a89703d
[alexxy/gromacs.git] / src / ngmx / popup.c
1 /*
2  * $Id$
3  * 
4  *       This source code is part of
5  * 
6  *        G   R   O   M   A   C   S
7  * 
8  * GROningen MAchine for Chemical Simulations
9  * 
10  *               VERSION 2.0
11  * 
12  * Copyright (c) 1991-1999
13  * BIOSON Research Institute, Dept. of Biophysical Chemistry
14  * University of Groningen, The Netherlands
15  * 
16  * Please refer to:
17  * GROMACS: A message-passing parallel molecular dynamics implementation
18  * H.J.C. Berendsen, D. van der Spoel and R. van Drunen
19  * Comp. Phys. Comm. 91, 43-56 (1995)
20  * 
21  * Also check out our WWW page:
22  * http://md.chem.rug.nl/~gmx
23  * or e-mail to:
24  * gromacs@chem.rug.nl
25  * 
26  * And Hey:
27  * Great Red Oystrich Makes All Chemists Sane
28  */
29 static char *SRCID_popup_c = "$Id$";
30
31 #include <string.h>
32 #include <math.h>
33 #include <macros.h>
34 #include <smalloc.h>
35 #include <x11.h>
36 #include <xutil.h>
37 #include "popup.h"
38
39 bool ChildCallBack(t_x11 *x11,XEvent *event, Window w, void *data)
40 {
41   t_child   *child;
42   t_mentry  *m;
43   t_windata *wd;
44   XEvent    letter;
45
46   child=(t_child *)data;
47   m=child->m;
48   wd=&(child->wd);
49   switch (event->type) {
50   case Expose:
51     XSetForeground(x11->disp,x11->gc,x11->fg);
52     TextInRect(x11,w,m->str,16,0,wd->width-16-2,wd->height-2,
53                eXLeft,eYCenter);
54     if (m->bChecked) {
55       int y=x11->font->ascent;
56       XDrawLine(x11->disp,w,x11->gc,2,(y*2)/3,6,y);
57       XDrawLine(x11->disp,w,x11->gc,3,(y*2)/3,7,y);
58       XDrawLine(x11->disp,w,x11->gc,7,y,12,2);
59     }
60     break;
61   case EnterNotify:
62     LightBorder(x11->disp,w,x11->fg);
63     break;
64   case LeaveNotify:
65     LightBorder(x11->disp,w,x11->bg);
66     break;
67   case ButtonRelease:
68     letter.type=ClientMessage;
69     letter.xclient.display=x11->disp;
70     letter.xclient.window=m->send_to ? m->send_to : child->Parent;
71     letter.xclient.message_type=0;
72     letter.xclient.format=32;
73     letter.xclient.data.l[0]=m->nreturn;
74     XSendEvent(x11->disp,letter.xclient.window,True,0,&letter);
75     break;
76   default:
77     break;
78   }
79   return FALSE;
80 }
81
82 bool MenuCallBack(t_x11 *x11,XEvent *event, Window w, void *data)
83 {
84   t_menu *m;
85
86   m=(t_menu *)data;
87   switch(event->type) {
88   case Expose:
89     /* Nothing to be done */
90     if (m->bGrabbed)
91       m->bGrabbed=
92         GrabOK(stderr,XGrabPointer(x11->disp,m->wd.self,True,
93                                    ButtonReleaseMask,GrabModeAsync,
94                                    GrabModeAsync,m->wd.self,None,CurrentTime));
95     break;
96   case ButtonRelease:
97     hide_menu(x11,m);
98     break;
99   case ClientMessage:
100     event->xclient.window=m->Parent;
101     XSendEvent(x11->disp,m->Parent,True,0,event);
102     break;
103   default:
104     break;
105   }
106   return FALSE;
107 }
108
109 t_menu *init_menu(t_x11 *x11,Window Parent,unsigned long fg,unsigned long bg,
110                   int nent,t_mentry ent[],int ncol)
111 {
112   int       i,mlen,mht,area,ht;
113   int       j,k,l;
114   int       frows,fcol;
115   t_menu    *m;
116   t_child   *kid;
117   t_windata *w;
118
119   snew(m,1);
120   m->nitem=nent;
121   m->Parent=Parent;
122
123   /* Calculate dimensions of the menu */
124   mlen=0;
125   for(i=0; (i<nent); i++)
126     mlen=max(mlen,XTextWidth(x11->font,ent[i].str,strlen(ent[i].str)));
127   mht=XTextHeight(x11->font);
128   /* Now we have the biggest single box, add a border of 2 pixels */
129   mlen+=20; /* We need extra space at the left for checkmarks */
130   mht+=4;
131   /* Calculate the area of the menu */
132   area=mlen*mht;
133   ht=sqrt(area);
134   /* No the number of rows per column, only beyond 8 rows */
135   if (ncol == 0) {
136     if (nent > 8)
137       frows=(1+ht/mht);
138     else
139       frows=nent;
140     fcol=nent/frows;
141   }
142   else {
143     fcol=ncol;
144     frows=nent/ncol;
145     if (nent % ncol)
146       frows++;
147   }
148   InitWin(&(m->wd),10,10,fcol*mlen,frows*mht,1,"Menu");
149   snew(m->item,nent);
150   m->wd.self=XCreateSimpleWindow(x11->disp,Parent,
151                                  m->wd.x, m->wd.y,
152                                  m->wd.width,m->wd.height,
153                                  m->wd.bwidth,fg,bg);
154   x11->RegisterCallback(x11,m->wd.self,Parent,MenuCallBack,m);
155   x11->SetInputMask(x11,m->wd.self,ExposureMask | 
156                     OwnerGrabButtonMask | ButtonReleaseMask);
157
158   for(j=l=0; (j<fcol); j++)
159     for(k=0; (k<frows) && (l<nent); k++,l++) {
160       kid=&(m->item[l]);
161       kid->m=&(ent[l]);
162       kid->Parent=Parent; 
163       w=&(kid->wd);
164       InitWin(w,j*mlen,k*mht,mlen-2,mht-2,1,NULL);
165       w->self=XCreateSimpleWindow(x11->disp,m->wd.self,
166                                   w->x,w->y,w->width,w->height,
167                                   w->bwidth,bg,bg);
168       x11->RegisterCallback(x11,w->self,m->wd.self,
169                             ChildCallBack,kid);
170       x11->SetInputMask(x11,w->self,
171                         ButtonPressMask | ButtonReleaseMask | 
172                         OwnerGrabButtonMask | ExposureMask | 
173                         EnterWindowMask | LeaveWindowMask);
174     }
175
176   return m;
177 }
178
179 void show_menu(t_x11 *x11,t_menu *m,int x,int y,bool bGrab)
180 {
181   XMoveWindow(x11->disp,m->wd.self,x,y);
182   m->bGrabbed=bGrab;
183   XMapWindow(x11->disp,m->wd.self);
184   XMapSubwindows(x11->disp,m->wd.self);
185 }
186
187 void hide_menu(t_x11 *x11,t_menu *m)
188 {
189   if (m->bGrabbed)
190     XUngrabPointer(x11->disp,CurrentTime);
191   XUnmapWindow(x11->disp,m->wd.self);
192 }
193
194 void check_menu_item(t_menu *m,int nreturn,bool bStatus)
195 {
196   int i;
197
198   for(i=0; (i<m->nitem); i++)
199     if(m->item[i].m->nreturn==nreturn)
200       m->item[i].m->bChecked=bStatus;
201 }
202
203 void done_menu(t_x11 *x11,t_menu *m)
204 {
205   int i;
206
207   for(i=0; (i<m->nitem); i++)
208     x11->UnRegisterCallback(x11,m->item[i].wd.self);
209   sfree(m->item);
210   x11->UnRegisterCallback(x11,m->wd.self);
211   sfree(m);
212 }
213
214 int menu_width(t_menu *m)
215 {
216   return m->wd.width;
217 }
218
219 int menu_height(t_menu *m)
220 {
221   return m->wd.height;
222 }
223