Add missing defines to PKG_CFLAGS
[gromacs.git] / src / ngmx / xdlg.c
blobec53bb8779fba28424e417b86fdd4d8eeac0ee3d
1 /*
2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include "string2.h"
46 #include "macros.h"
47 #include "smalloc.h"
48 #include "Xstuff.h"
49 #include "xutil.h"
50 #include "xdlg.h"
51 #include "xmb.h"
52 #include "gmx_fatal.h"
53 /*****************************
55 * Helpful routines
57 ****************************/
58 t_dlgitem *FindItem(t_dlg *dlg, t_id id)
60 int i;
62 for(i=0; (i<dlg->nitem); i++)
63 if (dlg->dlgitem[i]->ID==id)
64 return dlg->dlgitem[i];
65 return NULL;
68 t_dlgitem *FindWin(t_dlg *dlg, Window win)
70 int i;
72 for(i=0; (i<dlg->nitem); i++)
73 if (dlg->dlgitem[i]->win.self==win)
74 return dlg->dlgitem[i];
75 return NULL;
78 /*****************************
80 * Routines to manipulate items on a dialog box
82 ****************************/
83 gmx_bool QueryDlgItemSize(t_dlg *dlg,t_id id,int *w,int *h)
85 t_dlgitem *dlgitem;
87 if ((dlgitem=FindItem(dlg,id)) != NULL) {
88 *w=dlgitem->win.width;
89 *h=dlgitem->win.height;
90 return TRUE;
92 return FALSE;
95 gmx_bool QueryDlgItemPos(t_dlg *dlg,t_id id,int *x0,int *y0)
97 t_dlgitem *dlgitem;
99 if ((dlgitem=FindItem(dlg,id)) != NULL) {
100 *x0=dlgitem->win.x;
101 *y0=dlgitem->win.y;
102 return TRUE;
104 return FALSE;
107 int QueryDlgItemX(t_dlg *dlg, t_id id)
109 t_dlgitem *dlgitem;
111 if ((dlgitem=FindItem(dlg,id)) != NULL)
112 return dlgitem->win.x;
113 return 0;
116 int QueryDlgItemY(t_dlg *dlg, t_id id)
118 t_dlgitem *dlgitem;
120 if ((dlgitem=FindItem(dlg,id)) != NULL)
121 return dlgitem->win.y;
122 return 0;
125 int QueryDlgItemW(t_dlg *dlg, t_id id)
127 t_dlgitem *dlgitem;
129 if ((dlgitem=FindItem(dlg,id)) != NULL)
130 return dlgitem->win.width;
131 return 0;
134 int QueryDlgItemH(t_dlg *dlg, t_id id)
136 t_dlgitem *dlgitem;
138 if ((dlgitem=FindItem(dlg,id)) != NULL)
139 return dlgitem->win.height;
140 return 0;
143 gmx_bool SetDlgItemSize(t_dlg *dlg,t_id id,int w,int h)
145 t_dlgitem *dlgitem;
146 #ifdef DEBUG
147 int old_w, old_h;
148 #endif
150 if ((dlgitem=FindItem(dlg,id)) != NULL) {
151 #ifdef DEBUG
152 old_w=dlgitem->win.width;
153 old_h=dlgitem->win.height;
154 #endif
155 if (w)
156 dlgitem->win.width=w;
157 if (h)
158 dlgitem->win.height=h;
159 #ifdef DEBUG
160 fprintf(dlg->x11->console,
161 "Size window from: %dx%d to %dx%d\n",old_w,old_h,
162 dlgitem->win.width,dlgitem->win.height);
163 dlg->x11->Flush(dlg->x11);
164 #endif
165 if (dlgitem->win.self)
166 XResizeWindow(dlg->x11->disp,dlgitem->win.self,dlgitem->win.width,
167 dlgitem->win.height);
168 if ((w) && (dlgitem->type==edlgGB)) {
169 int i;
170 t_id gid=dlgitem->GroupID;
171 t_id id=dlgitem->ID;
172 for (i=0; (i<dlg->nitem); i++) {
173 t_dlgitem *child=dlg->dlgitem[i];
174 if ((child->GroupID==gid) && (child->ID!=id))
175 SetDlgItemSize(dlg,child->ID,w-4*OFFS_X,0);
178 return TRUE;
180 return FALSE;
183 gmx_bool SetDlgItemPos(t_dlg *dlg,t_id id,int x0,int y0)
185 t_dlgitem *dlgitem;
186 int old_x,old_y;
188 if ((dlgitem=FindItem(dlg,id)) != NULL) {
189 old_x=dlgitem->win.x;
190 old_y=dlgitem->win.y;
191 dlgitem->win.x=x0;
192 dlgitem->win.y=y0;
193 #ifdef DEBUG
194 fprintf(dlg->x11->console,
195 "Move window from: %d,%d to %d,%d\n",old_x,old_y,x0,y0);
196 dlg->x11->Flush(dlg->x11);
197 #endif
198 if (dlgitem->win.self)
199 XMoveWindow(dlg->x11->disp,dlgitem->win.self,x0,y0);
200 if (dlgitem->type==edlgGB) {
201 int i,x,y;
202 t_id gid=dlgitem->GroupID;
203 t_id id=dlgitem->ID;
204 x=dlgitem->win.x+2*OFFS_X-old_x;
205 y=dlgitem->win.y+2*OFFS_Y-old_y;
206 for (i=0; (i<dlg->nitem); i++) {
207 t_dlgitem *child=dlg->dlgitem[i];
208 if ((child->GroupID==gid) && (child->ID!=id))
209 SetDlgItemPos(dlg,child->ID,child->win.x+x,child->win.y+y);
212 return TRUE;
214 return FALSE;
217 /*****************************
219 * Routines to extract information from the dlg proc
220 * after dlg is exec'ed
222 ****************************/
223 gmx_bool IsCBChecked(t_dlg *dlg,t_id id)
225 t_dlgitem *dlgitem;
227 if ((dlgitem=FindItem(dlg,id)) != NULL)
228 if (dlgitem->type==edlgCB)
229 return dlgitem->u.checkbox.bChecked;
231 return FALSE;
234 t_id RBSelected(t_dlg *dlg,int gid)
236 int i;
238 for(i=0; (i<dlg->nitem); i++)
239 if ((dlg->dlgitem[i]->type==edlgRB) &&
240 (dlg->dlgitem[i]->u.radiobutton.bSelect) &&
241 (dlg->dlgitem[i]->GroupID==gid))
242 return dlg->dlgitem[i]->ID;
244 return -1;
247 int EditTextLen(t_dlg *dlg,t_id id)
249 t_dlgitem *dlgitem;
251 if ((dlgitem=FindItem(dlg,id)) != NULL)
252 if (dlgitem->type==edlgET)
253 return strlen(dlgitem->u.edittext.buf);
255 return 0;
258 char *EditText(t_dlg *dlg,t_id id)
260 t_dlgitem *dlgitem;
262 if ((dlgitem=FindItem(dlg,id)) != NULL)
263 if (dlgitem->type==edlgET)
264 return dlgitem->u.edittext.buf;
266 return NULL;
269 /*****************************
271 * Exececute the dialog box procedure
272 * Returns when a button is pushed.
273 * return value is the ID of the button
275 ****************************/
276 void ShowDlg(t_dlg *dlg)
278 int i;
279 t_dlgitem *dlgitem;
281 XMapWindow(dlg->x11->disp,dlg->win.self);
282 XMapSubwindows(dlg->x11->disp,dlg->win.self);
283 for (i=0; (i<dlg->nitem); i++)
284 LightBorder(dlg->x11->disp,dlg->dlgitem[i]->win.self,dlg->bg);
285 XSetForeground(dlg->x11->disp,dlg->x11->gc,dlg->x11->fg);
286 for(i=0; (i<dlg->nitem); i++) {
287 dlgitem=dlg->dlgitem[i];
288 if ((dlgitem->type==edlgBN) &&
289 (dlgitem->u.button.bDefault)) {
290 PushMouse(dlg->x11->disp,dlgitem->win.self,
291 dlgitem->win.width/2,dlgitem->win.height/2);
292 dlg->bPop=TRUE;
293 break;
296 dlg->bGrab=FALSE;
299 void HideDlg(t_dlg *dlg)
301 if (dlg->bPop)
302 PopMouse(dlg->x11->disp);
304 XUnmapSubwindows(dlg->x11->disp,dlg->win.self);
305 XUnmapWindow(dlg->x11->disp,dlg->win.self);
308 void NoHelp(t_dlg *dlg)
310 char **lines=NULL;
312 snew(lines,2);
313 lines[0]=strdup("Error");
314 lines[1]=strdup("No help for this item");
315 MessageBox(dlg->x11,dlg->wDad,"No Help",2,lines,
316 MB_OK | MB_ICONSTOP | MB_APPLMODAL,NULL,NULL);
317 sfree(lines[0]);
318 sfree (lines[1]);
319 sfree(lines);
322 void HelpDlg(t_dlg *dlg)
324 char *lines[] = {
325 "Place the cursor over one of the items",
326 "and press the F1 key to get more help.",
327 "First press the OK button."
329 MessageBox(dlg->x11,dlg->win.self,"Help Dialogbox",
330 3,lines,MB_OK | MB_ICONINFORMATION | MB_APPLMODAL,NULL,NULL);
333 void HelpNow(t_dlg *dlg, t_dlgitem *dlgitem)
335 char buf[80];
336 gmx_bool bCont=TRUE;
337 int i,nlines=0;
338 char **lines=NULL;
340 if (!dlgitem->help) {
341 NoHelp(dlg);
342 return;
345 printf("%s\n",dlgitem->help);
346 do {
347 fgets2(buf,79,stdin);
348 #ifdef DEBUG
349 fprintf(dlg->x11->console,"buffer: '%s'\n",buf);
350 dlg->x11->Flush(dlg->x11);
351 #endif
352 if (gmx_strcasecmp(buf,"nok")==0) {
353 /* An error occurred */
354 for(i=0; (i<nlines); i++)
355 sfree(lines[i]);
356 sfree(lines);
357 NoHelp(dlg);
358 return;
360 else {
361 bCont=(gmx_strcasecmp(buf,"ok") != 0);
362 if (bCont) {
363 srenew(lines,++nlines);
364 lines[nlines-1]=strdup(buf);
367 } while (bCont);
368 MessageBox(dlg->x11,dlg->wDad,"Help",
369 nlines,lines,MB_OK | MB_ICONINFORMATION | MB_APPLMODAL,NULL,NULL);
370 for(i=0; (i<nlines); i++)
371 sfree(lines[i]);
372 sfree(lines);
375 static void EnterDlg(t_dlg *dlg)
377 if (dlg->flags & DLG_APPLMODAL)
378 dlg->bGrab=GrabOK(dlg->x11->console,
379 XGrabPointer(dlg->x11->disp,dlg->win.self,
380 True,0,GrabModeAsync,GrabModeAsync,
381 dlg->win.self,None,CurrentTime));
382 dlg->x11->Flush(dlg->x11);
385 static void ExitDlg(t_dlg *dlg)
387 if (dlg->bGrab) {
388 XUngrabPointer(dlg->x11->disp,CurrentTime);
389 dlg->bGrab=FALSE;
391 HideDlg(dlg);
392 if (dlg->flags & DLG_FREEONBUTTON)
393 FreeDlg(dlg);
396 static gmx_bool DlgCB(t_x11 *x11,XEvent *event, Window w, void *data)
398 t_dlg *dlg=(t_dlg *)data;
399 int i,nWndProc;
400 t_dlgitem *dlgitem;
402 if ((dlgitem=FindWin(dlg,w))!=NULL) {
403 nWndProc=(dlgitem->WndProc)(x11,dlgitem,event);
404 #ifdef DEBUG
405 fprintf(x11->console,
406 "window: %s, nWndProc: %d\n",dlgitem->win.text,nWndProc);
407 x11->Flush(x11);
408 #endif
409 switch (nWndProc) {
410 case ENTERPRESSED:
411 if ((dlgitem->type==edlgBN) && (dlgitem->u.button.bDefault)) {
412 if (dlg->cb)
413 dlg->cb(x11,DLG_EXIT,dlgitem->ID,dlgitem->win.text,dlg->data);
414 else
415 ExitDlg(dlg);
417 else {
418 for(i=0; (i<dlg->nitem); i++)
419 if ((dlg->dlgitem[i]->type==edlgBN) &&
420 (dlg->dlgitem[i]->u.button.bDefault)) {
421 PushMouse(x11->disp,dlg->dlgitem[i]->win.self,
422 dlg->dlgitem[i]->win.width/2,
423 dlg->dlgitem[i]->win.height/2);
424 break;
427 break;
428 case BNPRESSED:
429 if (dlg->cb)
430 dlg->cb(x11,DLG_EXIT,dlgitem->ID,dlgitem->win.text,dlg->data);
431 else
432 ExitDlg(dlg);
433 break;
434 case RBPRESSED: {
435 int gid=dlgitem->GroupID;
436 t_id tid=RBSelected(dlg,gid);
437 #ifdef DEBUG
438 fprintf(stderr,"RBPRESSED\n");
439 #endif
440 if (tid != -1) {
441 t_dlgitem *dit=FindItem(dlg,tid);
442 dit->u.radiobutton.bSelect=FALSE;
443 ExposeWin(x11->disp,dit->win.self);
445 else
446 gmx_fatal(FARGS,"No RB Selected initially!\n");
447 dlgitem->u.radiobutton.bSelect=TRUE;
448 ExposeWin(x11->disp,dlgitem->win.self);
449 if (dlg->cb)
450 dlg->cb(x11,DLG_SET,dlgitem->ID,dlgitem->win.text,dlg->data);
451 break;
453 case CBPRESSED:
454 ExposeWin(x11->disp,dlgitem->win.self);
455 if (dlg->cb)
456 dlg->cb(x11,DLG_SET,dlgitem->ID,dlgitem->set,dlg->data);
457 break;
458 case ETCHANGED:
459 ExposeWin(x11->disp,dlgitem->win.self);
460 if (dlg->cb)
461 dlg->cb(x11,DLG_SET,dlgitem->ID,dlgitem->u.edittext.buf,dlg->data);
462 break;
463 case HELPPRESSED:
464 HelpNow(dlg,dlgitem);
465 break;
466 case ITEMOK:
467 break;
468 default:
469 gmx_fatal(FARGS,"Invalid return code (%d) from wndproc\n",nWndProc);
472 else if (w==dlg->win.self) {
473 switch(event->type) {
474 case Expose:
475 EnterDlg(dlg);
476 break;
477 case ButtonPress:
478 case KeyPress:
479 if (HelpPressed(event))
480 HelpDlg(dlg);
481 else
482 XBell(x11->disp,50);
483 break;
484 default:
485 break;
488 return FALSE;
491 /*****************************
493 * Routine to add an item to the dialog box
494 * The pointer to the item is copied to the dlg struct,
495 * the item itself may not be freed until the dlg is done with
497 ****************************/
498 void DoCreateDlg(t_dlg *dlg)
500 XSizeHints hints;
501 XSetWindowAttributes attr;
502 unsigned long Val;
504 attr.border_pixel=dlg->x11->fg;
505 attr.background_pixel=dlg->bg;
506 attr.override_redirect=False;
507 attr.save_under=True;
508 attr.cursor=XCreateFontCursor(dlg->x11->disp,XC_hand2);
509 Val=CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWSaveUnder |
510 CWCursor;
511 dlg->win.self=XCreateWindow(dlg->x11->disp,dlg->wDad,
512 dlg->win.x,dlg->win.y,
513 dlg->win.width,dlg->win.height,
514 dlg->win.bwidth,CopyFromParent,
515 InputOutput,CopyFromParent,
516 Val,&attr);
517 dlg->x11->RegisterCallback(dlg->x11,dlg->win.self,dlg->wDad,
518 DlgCB,dlg);
519 dlg->x11->SetInputMask(dlg->x11,dlg->win.self,
520 ExposureMask | ButtonPressMask | KeyPressMask);
522 if (!CheckWindow(dlg->win.self))
523 exit(1);
524 hints.x=dlg->win.x;
525 hints.y=dlg->win.y;
526 hints.flags=PPosition;
527 XSetStandardProperties(dlg->x11->disp,dlg->win.self,dlg->title,
528 dlg->title,None,NULL,0,&hints);
531 void AddDlgItem(t_dlg *dlg, t_dlgitem *item)
533 #define EnterLeaveMask (EnterWindowMask | LeaveWindowMask)
534 #define UserMask (ButtonPressMask | KeyPressMask)
535 static unsigned long InputMask[edlgNR] = {
536 ExposureMask | UserMask | EnterLeaveMask, /* edlgBN */
537 ExposureMask | UserMask | EnterLeaveMask, /* edlgRB */
538 ExposureMask, /* edlgGB */
539 ExposureMask | UserMask | EnterLeaveMask, /* edlgCB */
540 0, /* edlgPM */
541 ExposureMask, /* edlgST */
542 ExposureMask | UserMask | EnterLeaveMask /* edlgET */
545 if (!dlg->win.self)
546 DoCreateDlg(dlg);
547 srenew(dlg->dlgitem,dlg->nitem+1);
548 if (!item)
549 gmx_fatal(FARGS,"dlgitem not allocated");
550 item->win.self=
551 XCreateSimpleWindow(dlg->x11->disp,dlg->win.self,item->win.x,item->win.y,
552 item->win.width,item->win.height,
553 item->win.bwidth,dlg->x11->fg,dlg->x11->bg);
554 CheckWindow(item->win.self);
556 dlg->x11->RegisterCallback(dlg->x11,item->win.self,dlg->win.self,
557 DlgCB,dlg);
558 dlg->x11->SetInputMask(dlg->x11,item->win.self,InputMask[item->type]);
560 switch (item->type) {
561 case edlgPM:
562 XSetWindowBackgroundPixmap(dlg->x11->disp,item->win.self,item->u.pixmap.pm);
563 break;
564 default:
565 break;
567 dlg->dlgitem[dlg->nitem]=item;
569 dlg->nitem++;
572 void AddDlgItems(t_dlg *dlg,int nitem,t_dlgitem *item[])
574 int i;
576 for(i=0; (i<nitem); i++) {
577 #ifdef DEBUG
578 fprintf(dlg->x11->console,
579 "Adding item: %d from group %d\n",item[i]->ID,item[i]->GroupID);
580 dlg->x11->Flush(dlg->x11);
581 #endif
582 AddDlgItem(dlg,item[i]);
586 void FreeDlgItem(t_dlg *dlg, t_id id)
588 t_dlgitem *dlgitem;
589 int i;
591 if ((dlgitem=FindItem(dlg,id)) != NULL) {
592 dlg->x11->UnRegisterCallback(dlg->x11,dlgitem->win.self);
593 if (dlgitem->win.self)
594 XDestroyWindow(dlg->x11->disp,dlgitem->win.self);
595 FreeWin(dlg->x11->disp,&(dlgitem->win));
596 switch(dlgitem->type) {
597 case edlgBN:
598 case edlgRB:
599 break;
600 case edlgGB:
601 sfree(dlgitem->u.groupbox.item);
602 break;
603 case edlgCB:
604 break;
605 case edlgPM:
606 XFreePixmap(dlg->x11->disp,dlgitem->u.pixmap.pm);
607 break;
608 case edlgST:
609 for (i=0; (i<dlgitem->u.statictext.nlines); i++)
610 sfree(dlgitem->u.statictext.lines[i]);
611 sfree(dlgitem->u.statictext.lines);
612 break;
613 case edlgET:
614 sfree(dlgitem->u.edittext.buf);
615 break;
616 default:
617 break;
622 void FreeDlg(t_dlg *dlg)
624 int i;
626 if (dlg->dlgitem) {
627 HideDlg(dlg);
628 dlg->x11->UnRegisterCallback(dlg->x11,dlg->win.self);
629 for(i=0; (i<dlg->nitem); i++) {
630 FreeDlgItem(dlg,dlg->dlgitem[i]->ID);
631 if (dlg->dlgitem[i])
632 sfree(dlg->dlgitem[i]);
634 sfree(dlg->dlgitem);
635 if (dlg->win.self)
636 XDestroyWindow(dlg->x11->disp,dlg->win.self);
637 dlg->dlgitem=NULL;
641 /*****************************
643 * Routine to create the DLG structure, returns NULL on failure
645 ****************************/
646 t_dlg *CreateDlg(t_x11 *x11, Window Parent, const char *title,
647 int x0,int y0,int w,int h,int bw, unsigned long fg, unsigned long bg,
648 DlgCallback *cb,void *data)
650 t_dlg *dlg;
651 int x=0,y=0;
653 snew(dlg,1);
654 dlg->x11=x11;
655 dlg->cb=cb;
656 dlg->data=data;
657 if (title)
658 dlg->title=strdup(title);
659 else
660 dlg->title=NULL;
661 if (w==0) w=1;
662 if (h==0) h=1;
663 if (!Parent) {
664 Parent=x11->root;
665 dlg->xmax=DisplayWidth(x11->disp,x11->screen);
666 dlg->ymax=DisplayHeight(x11->disp,x11->screen);
668 else {
669 Window root;
670 unsigned int dum;
672 XGetGeometry(x11->disp,Parent,&root,&x,&y,
673 &(dlg->xmax),&(dlg->ymax),&dum,&dum);
674 #ifdef DEBUG
675 fprintf(x11->console,
676 "Daddy is %d x %d at %d, %d\n",dlg->xmax,dlg->ymax,x,y);
677 dlg->x11->Flush(dlg->x11);
678 #endif
680 if (x0) x=x0;
681 if (y0) y=y0;
682 InitWin(&(dlg->win),x,y,w,h,bw,NULL);
683 SetDlgSize(dlg,w,h,x0 || y0);
685 dlg->wDad=Parent;
686 dlg->fg=x11->fg;
687 dlg->bg=x11->bg;
688 dlg->nitem=0;
689 dlg->dlgitem=NULL;
691 DoCreateDlg(dlg);
692 return dlg;
695 void SetDlgSize(t_dlg *dlg,int w,int h, gmx_bool bAutoPosition)
697 if (bAutoPosition) {
698 int x,y;
700 x=(dlg->xmax-w)/2;
701 y=(dlg->ymax-h)/2;
702 dlg->win.x=x;
703 dlg->win.y=y;
705 dlg->win.width=w;
706 dlg->win.height=h;
708 #ifdef DEBUG
709 fprintf(dlg->x11->console,"SetDlgSize: Dialog is %dx%d, at %d,%d\n",
710 dlg->win.width,dlg->win.height,dlg->win.x,dlg->win.y);
711 dlg->x11->Flush(dlg->x11);
712 #endif
713 if (dlg->win.self) {
714 XMoveWindow(dlg->x11->disp,dlg->win.self,dlg->win.x,dlg->win.y);
715 XResizeWindow(dlg->x11->disp,dlg->win.self,w,h);