46dbe856d58a3d7676d44a9fc79d357ffde09b8c
[alexxy/gromacs.git] / src / ngmx / xdlgitem.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_xdlgitem_c = "$Id$";
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "string2.h"
36 #include "assert.h"
37 #include "smalloc.h"
38 #include "macros.h"
39 #include "Xstuff.h"
40 #include "xdlgitem.h"
41
42 #define BUFSIZE 16
43
44 t_dlgitem *newitem(t_x11 *x11)
45 {
46   t_dlgitem *item;
47   
48   snew(item,1);
49   
50   return item;
51 }
52
53 /*****************************
54  *
55  * Window Procedures and helpful functions
56  *
57  ****************************/
58 static void ShowCaret(t_x11 *x11, t_dlgitem *dlgitem)
59 {
60   t_edittext *et;
61
62   if (dlgitem->type == edlgET) {
63     int x,y1,y2;
64     
65     et=&(dlgitem->u.edittext);
66     x=XTextWidth(x11->font,dlgitem->win.text,strlen(dlgitem->win.text))+XCARET+
67       XTextWidth(x11->font,(char*) &(et->buf[et->strbegin]),et->pos);
68     y1=(dlgitem->win.height-XTextHeight(x11->font))/2;
69     y2=(dlgitem->win.height-y1);
70     y1--, y2++;
71     XDrawLine(x11->disp,dlgitem->win.self,x11->gc,x-XCARET,y1,x+XCARET,y1);
72     XDrawLine(x11->disp,dlgitem->win.self,x11->gc,x,y1,x,y2);
73     XDrawLine(x11->disp,dlgitem->win.self,x11->gc,x-XCARET,y2,x+XCARET,y2);
74   }
75 }
76
77 static void HideCaret(t_x11 *x11, t_dlgitem *dlgitem)
78 {
79   XSetForeground(x11->disp,x11->gc,x11->bg);
80   ShowCaret(x11,dlgitem);
81   XSetForeground(x11->disp,x11->gc,x11->fg);
82 }
83
84 static int DefWndProc(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
85 {
86   XComposeStatus status;
87   KeySym keysym;
88   char c[BUFSIZE+1];
89
90 #ifdef DEBUG
91   printf("DefWndProc\n");
92 #endif
93   switch(event->type) {
94   case Expose:
95   case ButtonPress:
96   case KeyPress:
97     if (HelpPressed(event))
98       return HELPPRESSED;
99     else {
100       XLookupString(&(event->xkey),c,BUFSIZE,&keysym,&status);
101       if ((keysym==XK_Return) || (keysym==XK_KP_Enter))
102         return ENTERPRESSED;
103     }
104     break;
105   case EnterNotify:
106     dlgitem->win.bFocus=TRUE;
107     ShowCaret(x11,dlgitem);
108     /*    LightBorder(x11->disp,dlgitem->win.self,x11->fg); */
109     break;
110   case LeaveNotify:
111     dlgitem->win.bFocus=FALSE;
112     HideCaret(x11,dlgitem);
113     /*    LightBorder(x11->disp,dlgitem->win.self,x11->bg); */
114     break;
115   default:
116     XBell(x11->disp,50);
117   }
118   return ITEMOK;
119 }
120
121 static int WndProcBN(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
122 {
123   t_windata *win;
124   int x,w,th;
125
126   assert(dlgitem->type==edlgBN);
127   win=&(dlgitem->win);
128   w=XTextWidth(x11->font,win->text,strlen(win->text));
129   x=(win->width-w)/2;
130   th=XTextHeight(x11->font)+OFFS_Y;
131   switch(event->type) {
132   case Expose:
133     RectWin(x11->disp,x11->gc,win,x11->fg);
134     TextInRect(x11,win->self,win->text,0,0,win->width,th,eXCenter,eYCenter);
135     break;
136   case ButtonPress:
137     return BNPRESSED;
138   case EnterNotify:
139     XDrawLine(x11->disp,win->self,x11->gc,x-1,th,x+w,th);
140     break;
141   case LeaveNotify:
142     XSetForeground(x11->disp,x11->gc,x11->bg);
143     XDrawLine(x11->disp,win->self,x11->gc,x-1,th,x+w,th);
144     XSetForeground(x11->disp,x11->gc,x11->fg);
145     break;
146   default: 
147     return DefWndProc(x11,dlgitem,event);
148   }
149   return ITEMOK;
150 }
151
152 static int WndProcRB(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
153 {
154   t_radiobutton *rb;
155   t_windata *win;
156   int x,y,rad;
157   
158   assert(dlgitem->type==edlgRB);
159   rb=&(dlgitem->u.radiobutton);
160   win=&(dlgitem->win);
161   
162   rad=win->height/3;
163   x=rad;
164   y=win->height/2;
165   switch(event->type) {
166   case Expose:
167     XClearArea(x11->disp,win->self,x-rad,y-rad,x+rad,y+rad,False);
168     if (rb->bSelect)
169       /* Filled */
170       XFillCircle(x11->disp,win->self,x11->gc,x,y,rad);
171     XDrawCircle(x11->disp,win->self,x11->gc,x,y,rad);
172     x+=rad+OFFS_X;
173     TextInRect(x11,win->self,win->text,x,0,win->width-x,win->height,
174                eXLeft,eYCenter);
175     break;
176   case ButtonPress:
177     if (!rb->bSelect)
178       return RBPRESSED;
179     XBell(x11->disp,50);
180     break;
181   case EnterNotify:
182   case LeaveNotify:
183     break;
184   default:
185     return DefWndProc(x11,dlgitem,event);
186   }
187   return ITEMOK;
188 }
189
190 static int WndProcGB(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
191 {
192   t_windata *win;
193   int x,y;
194
195   assert(dlgitem->type==edlgGB);
196   win=&(dlgitem->win);
197   
198   x=XTextWidth(x11->font,win->text,strlen(win->text));
199   y=XTextHeight(x11->font);
200   switch(event->type) {
201   case Expose:
202     XSetForeground(x11->disp,x11->gc,x11->fg);
203     XDrawRoundRect(x11->disp,win->self,x11->gc,0,y/2,
204                    win->width-1,win->height-y/2-1);
205     XClearArea(x11->disp,win->self,OFFS_X,0,x+OFFS_X,y,False);
206     TextInRect(x11,win->self,win->text,2*OFFS_X,0,x,y,eXCenter,eYCenter);
207     break;
208   case EnterNotify:
209   case LeaveNotify:
210     break;
211   default:
212     return DefWndProc(x11,dlgitem,event);
213   }
214   return ITEMOK;
215 }
216
217 static int WndProcCB(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
218 {
219   t_checkbox *cb;
220   t_windata *win;
221   int x,y,w,h;
222   
223   assert(dlgitem->type==edlgCB);
224   cb=&(dlgitem->u.checkbox);
225   win=&(dlgitem->win);
226
227   x=0;
228   y=win->height/7;
229   w=5*y;
230   h=5*y;
231   switch(event->type) {
232   case Expose:
233     XSetForeground(x11->disp,x11->gc,x11->fg);
234     XClearArea(x11->disp,win->self,x,y,w,h,False);
235     XDrawRectangle(x11->disp,win->self,x11->gc,x,y,w,h);
236     if (cb->bChecked) {
237       XDrawLine(x11->disp,win->self,x11->gc,x,y,x+w,y+h);
238       XDrawLine(x11->disp,win->self,x11->gc,x+w,y,x,y+h);
239     }
240     x=w+OFFS_X;
241     TextInRect(x11,win->self,win->text,x,0,win->width-x,win->height,
242                eXLeft,eYCenter);
243     break;
244   case ButtonPress:
245     cb->bChecked=!cb->bChecked;
246     return CBPRESSED;
247   case EnterNotify:
248   case LeaveNotify:
249     break;
250   default:
251     return DefWndProc(x11,dlgitem,event);
252   }
253   return ITEMOK;
254 }
255
256 static int WndProcST(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
257 {
258   t_statictext *st;
259   t_windata *win;
260   int i,dy;
261   
262   assert(dlgitem->type==edlgST);
263   st=&(dlgitem->u.statictext);
264   win=&(dlgitem->win);
265
266   switch(event->type) {
267   case Expose:
268     dy=XTextHeight(x11->font)+OFFS_Y;
269     for (i=0; (i<st->nlines); i++)
270       TextInRect(x11,win->self,st->lines[i],
271                  0,OFFS_Y+i*dy,win->width,dy,eXLeft,eYCenter);
272     break;
273   default:
274     return DefWndProc(x11,dlgitem,event);
275   }
276   return ITEMOK;
277 }
278
279 static bool insert(char *s, char c, int *pos)
280 {
281   int i,sl;
282
283   if (isprint(c)) {
284     sl=strlen(s);
285     /* +1 for zero termination */
286     for(i=sl+1; (i>*pos); i--)
287       s[i+1]=s[i];
288     s[*pos]=c;
289     (*pos)++;
290     return TRUE;
291   }
292   return FALSE;
293 }
294
295 static bool my_backspace(char *s, int *pos)
296 {
297   int i,sl;
298
299   sl=strlen(s);
300   if ((sl > 0) && ((*pos) > 0)) {
301     for(i=*pos-1; (i<sl); i++)
302       s[i]=s[i+1];
303     (*pos)=max(0,(*pos)-1);
304     return TRUE;
305   }
306   return FALSE;
307 }
308
309 static bool my_delete(char *s, int *pos)
310 {
311   int i,sl;
312
313   sl=strlen(s);
314   if ((sl > 0) && ((*pos) < sl)) {
315     for(i=*pos; (i<sl); i++)
316       s[i]=s[i+1];
317     return TRUE;
318   }
319   return FALSE;
320 }
321
322 static int WndProcET(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
323 {
324   t_edittext *et;
325   t_windata  *win;
326   KeySym     keysym;
327   char       c[BUFSIZE+1],*bp;
328   char       scrbuf[STRLEN];
329   int        i,xp,xtitle,ewidth;
330   
331   assert(dlgitem->type==edlgET);
332   et=&(dlgitem->u.edittext);
333   win=&(dlgitem->win);
334
335   /* Copy string part that is visible into screen buffer */
336   for(i=0; (i<et->buflen); i++)
337     scrbuf[i]=et->buf[i+et->strbegin];
338   scrbuf[i]='\0';
339
340   switch(event->type) {
341   case Expose:
342     XSetForeground(x11->disp,x11->gc,x11->fg);
343     xtitle=XTextWidth(x11->font,win->text,strlen(win->text));
344     ewidth=win->width-xtitle;
345     TextInRect(x11,win->self,win->text,
346                0,0,xtitle-1,win->height,eXLeft,eYCenter);
347     XClearArea(x11->disp,win->self,xtitle,0,ewidth+XCARET,win->height,False);
348     TextInRect(x11,win->self,scrbuf,
349                xtitle+XCARET,0,ewidth,win->height,eXLeft,eYCenter);
350 #ifdef DEBUG
351     printf("Expose\n");
352 #endif
353     if (win->bFocus)
354       ShowCaret(x11,dlgitem);
355     break;
356   case ButtonPress:
357     /* Calculate new position for caret */
358     et->pos=strlen(et->buf);
359     bp=strdup(et->buf);
360     xp=event->xbutton.x-XTextWidth(x11->font,win->text,strlen(win->text))-
361       XCARET;
362     while ((et->pos > 0) && (XTextWidth(x11->font,bp,strlen(bp)) > xp)) {
363       et->pos--;
364       bp[et->pos]='\0';
365     }
366     sfree(bp);
367     et->bChanged=TRUE;
368     return ETCHANGED;
369   case KeyPress:
370     /* Check for HelpKey */
371     if (HelpPressed(event))
372       return DefWndProc(x11,dlgitem,event);
373     XLookupString(&(event->xkey),c,BUFSIZE,&keysym,NULL);
374 #ifdef DEBUG
375     printf("Keysym: %x\n",keysym);
376 #endif
377     switch(keysym) {
378     case XK_Delete:
379       if (my_delete(et->buf,&(et->pos))){
380         et->bChanged=TRUE;
381         return ETCHANGED;
382       }
383       else
384         XBell(x11->disp,50);
385       break;
386     case XK_BackSpace:
387       if (my_backspace(et->buf,&(et->pos))) {
388         et->bChanged=TRUE;
389         return ETCHANGED;
390       }
391       else
392         XBell(x11->disp,50);
393       break;
394     case XK_KP_Enter:
395     case XK_Return:
396       return ENTERPRESSED;
397     case XK_Home:
398       et->pos=0;
399       et->strbegin=0;
400       et->bChanged=TRUE;
401       return ETCHANGED;
402     case XK_End:
403       if (strlen(et->buf) <= et->buflen)
404         et->pos=strlen(et->buf);
405       else {
406         et->pos=et->buflen;
407         et->strbegin=strlen(et->buf)-et->buflen;
408       }
409       et->bChanged=TRUE;
410       return ETCHANGED;
411     case XK_Left:
412       et->pos=max(0,et->pos-1);
413       et->strbegin=min(et->strbegin,et->pos);
414       et->bChanged=TRUE;
415       return ETCHANGED;
416     case XK_Right:
417       if ((et->pos < et->buflen) && (et->strbegin+et->buflen > strlen(et->buf)))
418         et->pos++;
419       else if ((et->buflen   < strlen(et->buf)) && 
420                (et->strbegin < strlen(et->buf)-et->buflen))
421         et->strbegin++;
422       else
423         break;
424       et->bChanged=TRUE;
425       return ETCHANGED;
426     default:
427       if (keysym < 256) 
428         if (insert(et->buf,c[0],&(et->pos))) {
429           et->bChanged=TRUE;
430           return ETCHANGED;
431         }
432       XBell(x11->disp,50);
433       break;
434     }
435     break;
436   case LeaveNotify:
437     win->bFocus=FALSE;
438     HideCaret(x11,dlgitem);
439     if (et->bChanged)
440       et->bChanged=FALSE;
441     break;
442   default:
443     return DefWndProc(x11,dlgitem,event);
444   }
445   return ITEMOK;
446 }
447
448 /*****************************
449  *
450  * Routines to create dialog items, all items have an id
451  * which you can use to extract info. It is possible to have
452  * multiple items with the same id but it may then not be possible
453  * to extract information.
454  * All routines take the position relative to the parent dlg
455  * and the size and border width.
456  * If the width and height are set to zero initially, they will
457  * be calculated and set by the routine. With the dlgitem manipulation
458  * routines listed below, the application can then move the items around
459  * on the dlg box, and if wished resize them.
460  *
461  ****************************/
462 t_dlgitem *CreateButton(t_x11 *x11,
463                         char *szLab,bool bDef,t_id id,t_id groupid,
464                         int x0,int y0,int w,int h,int bw)
465 {
466   t_dlgitem *dlgitem;
467   char *lab;
468   
469   dlgitem=newitem(x11);
470   if (h==0) h=XTextHeight(x11->font)+2*OFFS_Y;
471   if (w==0) w=XTextWidth(x11->font,szLab,strlen(szLab))+2*OFFS_X;
472   if (bDef) {
473     snew(lab,strlen(szLab)+7); /* 6 for >> << and 1 for \0 */
474     sprintf(lab,">> %s <<",szLab);
475   }
476   else
477     lab=strdup(szLab);
478   InitWin(&(dlgitem->win),x0,y0,w,h,bw,szLab);
479   sfree(lab);
480   dlgitem->ID=id;
481   dlgitem->GroupID=groupid;
482   dlgitem->type=edlgBN;
483   dlgitem->u.button.bDefault=bDef;
484   dlgitem->WndProc=WndProcBN;
485   
486   return dlgitem;
487 }
488
489 t_dlgitem *CreateRadioButton(t_x11 *x11,
490                              char *szLab,bool bSet,t_id id,
491                              t_id groupid,
492                              int x0,int y0,int w,int h,int bw)
493 {
494   t_dlgitem *dlgitem;
495   
496   dlgitem=newitem(x11);
497   if (h==0) h=XTextHeight(x11->font)+OFFS_Y;
498   if (w==0) w=XTextWidth(x11->font,szLab,strlen(szLab))+OFFS_X+h;
499   InitWin(&(dlgitem->win),x0,y0,w,h,bw,szLab);
500   dlgitem->ID=id;
501   dlgitem->GroupID=groupid;
502   dlgitem->type=edlgRB;
503   dlgitem->u.radiobutton.bSelect=bSet;
504   dlgitem->WndProc=WndProcRB;
505
506   return dlgitem;
507 }
508
509 t_dlgitem *CreateGroupBox(t_x11 *x11,
510                           char *szLab,t_id id,
511                           int nitems, t_id items[],
512                           int x0,int y0,int w,int h,int bw)
513 {
514   t_dlgitem *dlgitem;
515
516   dlgitem=newitem(x11);
517   if (h==0) h=XTextHeight(x11->font)+OFFS_Y;
518   if (w==0) w=XTextWidth(x11->font,szLab,strlen(szLab))+2*OFFS_X;
519   InitWin(&(dlgitem->win),x0,y0,w,h,bw,szLab);
520   dlgitem->GroupID=id;
521   dlgitem->ID=id;
522   dlgitem->type=edlgGB;
523   dlgitem->u.groupbox.nitems=nitems;
524   snew(dlgitem->u.groupbox.item,nitems);
525   memcpy((char *)dlgitem->u.groupbox.item,(char *)items,
526          nitems*sizeof(items[0]));
527   dlgitem->WndProc=WndProcGB;
528
529   return dlgitem;
530 }
531
532 t_dlgitem *CreateCheckBox(t_x11 *x11,
533                           char *szLab,bool bCheckedInitial,t_id id,
534                           t_id groupid,
535                           int x0,int y0,int w,int h,int bw)
536 {
537   t_dlgitem *dlgitem;
538   
539   dlgitem=newitem(x11);
540   if (h==0) h=XTextHeight(x11->font)+OFFS_Y;
541   if (w==0) w=XTextWidth(x11->font,szLab,strlen(szLab))+OFFS_X+h;
542   InitWin(&(dlgitem->win),x0,y0,w,h,bw,szLab);
543   dlgitem->ID=id;
544   dlgitem->GroupID=groupid;
545   dlgitem->type=edlgCB;
546   dlgitem->u.checkbox.bChecked=bCheckedInitial;
547   dlgitem->WndProc=WndProcCB;
548  
549   return dlgitem;
550 }
551
552 t_dlgitem *CreatePixmap(t_x11 *x11,
553                         Pixmap pm,t_id id,
554                         t_id groupid,int x0,int y0,int w,int h,int bw)
555 {
556   t_dlgitem *dlgitem;
557   
558   dlgitem=newitem(x11);
559   InitWin(&(dlgitem->win),x0,y0,w,h,bw,NULL);
560   dlgitem->ID=id;
561   dlgitem->type=edlgPM;
562   dlgitem->u.pixmap.pm=pm;
563   dlgitem->WndProc=DefWndProc;
564   
565   return dlgitem;
566 }
567
568 t_dlgitem *CreateStaticText(t_x11 *x11,
569                             int nlines,char **lines,t_id id,t_id groupid,
570                             int x0,int y0,int w,int h,int bw)
571 {
572   t_dlgitem *dlgitem;
573   int i;
574   
575   dlgitem=newitem(x11);
576   if (h==0) h=(XTextHeight(x11->font)+OFFS_Y)*nlines+OFFS_Y;
577   if (w==0) {
578     for(i=0; (i<nlines); i++)
579       w=max(w,XTextWidth(x11->font,lines[i],strlen(lines[i])));
580     w+=2*OFFS_X;
581   }
582   InitWin(&(dlgitem->win),x0,y0,w,h,bw,NULL);
583   dlgitem->ID=id;
584   dlgitem->GroupID=groupid;
585   dlgitem->type=edlgST;
586   dlgitem->u.statictext.nlines=nlines;
587   snew(dlgitem->u.statictext.lines,nlines);
588   for(i=0; (i<nlines); i++)
589     dlgitem->u.statictext.lines[i]=strdup(lines[i]);
590   dlgitem->WndProc=WndProcST;
591  
592   return dlgitem;
593 }
594
595 t_dlgitem *CreateEditText(t_x11 *x11,
596                           char *title,
597                           int screenbuf,char *buf, t_id id,t_id groupid,
598                           int x0,int y0,int w,int h,int bw)
599 {
600   t_dlgitem *dlgitem;
601   t_edittext *et;
602   
603   dlgitem=newitem(x11);
604   if (h==0) h=XTextHeight(x11->font)+OFFS_Y;
605   if (w==0) {
606     char *test;
607
608     snew(test,screenbuf);
609     memset(test,'w',screenbuf);
610     w=XTextWidth(x11->font,test,screenbuf)+
611       XTextWidth(x11->font,title,strlen(title))+
612       2*XCARET+2*OFFS_X;
613     sfree(test);
614   }
615   InitWin(&(dlgitem->win),x0,y0,w,h,bw,title);
616   dlgitem->ID=id;
617   dlgitem->GroupID=groupid;
618   dlgitem->type=edlgET;
619   et=&(dlgitem->u.edittext);
620   snew(et->buf,STRLEN);
621   strcpy(et->buf,buf);
622   et->buflen=screenbuf;
623   et->strbegin=0;
624   et->bChanged=FALSE;
625   dlgitem->WndProc=WndProcET;
626
627   return dlgitem;
628 }
629
630 #define SC(src) (strlen(src)?strdup(src):NULL)
631
632 void SetDlgitemOpts(t_dlgitem *dlgitem,bool bUseMon,
633                     char *set,char *get,char *help)
634 {
635   dlgitem->bUseMon=bUseMon;
636   dlgitem->set=SC(set);
637   dlgitem->get=SC(get);
638   dlgitem->help=SC(help);
639 #ifdef DEBUG
640   printf("Help is: '%s'\n",dlgitem->help);
641 #endif
642 }