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 * Copyright (c) 2013,2014,2015,2017, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
45 #include "gromacs/utility/cstringutil.h"
46 #include "gromacs/utility/fatalerror.h"
47 #include "gromacs/utility/smalloc.h"
52 /*****************************
56 ****************************/
57 t_dlgitem
*FindItem(t_dlg
*dlg
, t_id id
)
61 for (i
= 0; (i
< dlg
->nitem
); i
++)
63 if (dlg
->dlgitem
[i
]->ID
== id
)
65 return dlg
->dlgitem
[i
];
71 t_dlgitem
*FindWin(t_dlg
*dlg
, Window win
)
75 for (i
= 0; (i
< dlg
->nitem
); i
++)
77 if (dlg
->dlgitem
[i
]->win
.self
== win
)
79 return dlg
->dlgitem
[i
];
85 /*****************************
87 * Routines to manipulate items on a dialog box
89 ****************************/
90 bool QueryDlgItemSize(t_dlg
*dlg
, t_id id
, int *w
, int *h
)
94 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
96 *w
= dlgitem
->win
.width
;
97 *h
= dlgitem
->win
.height
;
103 bool QueryDlgItemPos(t_dlg
*dlg
, t_id id
, int *x0
, int *y0
)
107 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
109 *x0
= dlgitem
->win
.x
;
110 *y0
= dlgitem
->win
.y
;
116 int QueryDlgItemX(t_dlg
*dlg
, t_id id
)
120 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
122 return dlgitem
->win
.x
;
127 int QueryDlgItemY(t_dlg
*dlg
, t_id id
)
131 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
133 return dlgitem
->win
.y
;
138 int QueryDlgItemW(t_dlg
*dlg
, t_id id
)
142 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
144 return dlgitem
->win
.width
;
149 int QueryDlgItemH(t_dlg
*dlg
, t_id id
)
153 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
155 return dlgitem
->win
.height
;
160 bool SetDlgItemSize(t_dlg
*dlg
, t_id id
, int w
, int h
)
167 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
170 old_w
= dlgitem
->win
.width
;
171 old_h
= dlgitem
->win
.height
;
175 dlgitem
->win
.width
= w
;
179 dlgitem
->win
.height
= h
;
182 std::fprintf(dlg
->x11
->console
,
183 "Size window from: %dx%d to %dx%d\n", old_w
, old_h
,
184 dlgitem
->win
.width
, dlgitem
->win
.height
);
185 dlg
->x11
->Flush(dlg
->x11
);
187 if (dlgitem
->win
.self
)
189 XResizeWindow(dlg
->x11
->disp
, dlgitem
->win
.self
, dlgitem
->win
.width
,
190 dlgitem
->win
.height
);
192 if ((w
) && (dlgitem
->type
== edlgGB
))
195 t_id gid
= dlgitem
->GroupID
;
196 t_id id
= dlgitem
->ID
;
197 for (i
= 0; (i
< dlg
->nitem
); i
++)
199 t_dlgitem
*child
= dlg
->dlgitem
[i
];
200 if ((child
->GroupID
== gid
) && (child
->ID
!= id
))
202 SetDlgItemSize(dlg
, child
->ID
, w
-4*OFFS_X
, 0);
211 bool SetDlgItemPos(t_dlg
*dlg
, t_id id
, int x0
, int y0
)
216 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
218 old_x
= dlgitem
->win
.x
;
219 old_y
= dlgitem
->win
.y
;
223 std::fprintf(dlg
->x11
->console
,
224 "Move window from: %d,%d to %d,%d\n", old_x
, old_y
, x0
, y0
);
225 dlg
->x11
->Flush(dlg
->x11
);
227 if (dlgitem
->win
.self
)
229 XMoveWindow(dlg
->x11
->disp
, dlgitem
->win
.self
, x0
, y0
);
231 if (dlgitem
->type
== edlgGB
)
234 t_id gid
= dlgitem
->GroupID
;
235 t_id id
= dlgitem
->ID
;
236 x
= dlgitem
->win
.x
+2*OFFS_X
-old_x
;
237 y
= dlgitem
->win
.y
+2*OFFS_Y
-old_y
;
238 for (i
= 0; (i
< dlg
->nitem
); i
++)
240 t_dlgitem
*child
= dlg
->dlgitem
[i
];
241 if ((child
->GroupID
== gid
) && (child
->ID
!= id
))
243 SetDlgItemPos(dlg
, child
->ID
, child
->win
.x
+x
, child
->win
.y
+y
);
252 /*****************************
254 * Routines to extract information from the dlg proc
255 * after dlg is exec'ed
257 ****************************/
258 bool IsCBChecked(t_dlg
*dlg
, t_id id
)
262 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
264 if (dlgitem
->type
== edlgCB
)
266 return dlgitem
->u
.checkbox
.bChecked
;
273 t_id
RBSelected(t_dlg
*dlg
, int gid
)
277 for (i
= 0; (i
< dlg
->nitem
); i
++)
279 if ((dlg
->dlgitem
[i
]->type
== edlgRB
) &&
280 (dlg
->dlgitem
[i
]->u
.radiobutton
.bSelect
) &&
281 (dlg
->dlgitem
[i
]->GroupID
== gid
))
283 return dlg
->dlgitem
[i
]->ID
;
290 int EditTextLen(t_dlg
*dlg
, t_id id
)
294 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
296 if (dlgitem
->type
== edlgET
)
298 return std::strlen(dlgitem
->u
.edittext
.buf
);
305 char *EditText(t_dlg
*dlg
, t_id id
)
309 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
311 if (dlgitem
->type
== edlgET
)
313 return dlgitem
->u
.edittext
.buf
;
320 /*****************************
322 * Exececute the dialog box procedure
323 * Returns when a button is pushed.
324 * return value is the ID of the button
326 ****************************/
327 void ShowDlg(t_dlg
*dlg
)
332 XMapWindow(dlg
->x11
->disp
, dlg
->win
.self
);
333 XMapSubwindows(dlg
->x11
->disp
, dlg
->win
.self
);
334 for (i
= 0; (i
< dlg
->nitem
); i
++)
336 LightBorder(dlg
->x11
->disp
, dlg
->dlgitem
[i
]->win
.self
, dlg
->bg
);
338 XSetForeground(dlg
->x11
->disp
, dlg
->x11
->gc
, dlg
->x11
->fg
);
339 for (i
= 0; (i
< dlg
->nitem
); i
++)
341 dlgitem
= dlg
->dlgitem
[i
];
342 if ((dlgitem
->type
== edlgBN
) &&
343 (dlgitem
->u
.button
.bDefault
))
345 PushMouse(dlg
->x11
->disp
, dlgitem
->win
.self
,
346 dlgitem
->win
.width
/2, dlgitem
->win
.height
/2);
354 void HideDlg(t_dlg
*dlg
)
358 PopMouse(dlg
->x11
->disp
);
361 XUnmapSubwindows(dlg
->x11
->disp
, dlg
->win
.self
);
362 XUnmapWindow(dlg
->x11
->disp
, dlg
->win
.self
);
365 void NoHelp(t_dlg
*dlg
)
367 const char *lines
[2] = {
369 "No help for this item"
371 MessageBox(dlg
->x11
, dlg
->wDad
, "No Help", 2, lines
,
372 MB_OK
| MB_ICONSTOP
| MB_APPLMODAL
, nullptr, nullptr);
375 void HelpDlg(t_dlg
*dlg
)
377 const char *lines
[] = {
378 "Place the cursor over one of the items",
379 "and press the F1 key to get more help.",
380 "First press the OK button."
382 MessageBox(dlg
->x11
, dlg
->win
.self
, "Help Dialogbox",
383 3, lines
, MB_OK
| MB_ICONINFORMATION
| MB_APPLMODAL
, nullptr, nullptr);
386 void HelpNow(t_dlg
*dlg
, t_dlgitem
*dlgitem
)
391 char **lines
= nullptr;
399 std::printf("%s\n", dlgitem
->help
);
402 fgets2(buf
, 79, stdin
);
404 std::fprintf(dlg
->x11
->console
, "buffer: '%s'\n", buf
);
405 dlg
->x11
->Flush(dlg
->x11
);
407 if (gmx_strcasecmp(buf
, "nok") == 0)
409 /* An error occurred */
412 for (i
= 0; (i
< nlines
); i
++)
423 bCont
= (gmx_strcasecmp(buf
, "ok") != 0);
426 srenew(lines
, ++nlines
);
427 lines
[nlines
-1] = gmx_strdup(buf
);
432 MessageBox(dlg
->x11
, dlg
->wDad
, "Help",
434 MB_OK
| MB_ICONINFORMATION
| MB_APPLMODAL
, nullptr, nullptr);
435 for (i
= 0; (i
< nlines
); i
++)
442 static void EnterDlg(t_dlg
*dlg
)
444 if (dlg
->flags
& DLG_APPLMODAL
)
446 dlg
->bGrab
= GrabOK(dlg
->x11
->console
,
447 XGrabPointer(dlg
->x11
->disp
, dlg
->win
.self
,
448 True
, 0, GrabModeAsync
, GrabModeAsync
,
449 dlg
->win
.self
, None
, CurrentTime
));
451 dlg
->x11
->Flush(dlg
->x11
);
454 static void ExitDlg(t_dlg
*dlg
)
458 XUngrabPointer(dlg
->x11
->disp
, CurrentTime
);
462 if (dlg
->flags
& DLG_FREEONBUTTON
)
468 static bool DlgCB(t_x11
*x11
, XEvent
*event
, Window w
, void *data
)
470 t_dlg
*dlg
= (t_dlg
*)data
;
474 if ((dlgitem
= FindWin(dlg
, w
)) != nullptr)
476 nWndProc
= (dlgitem
->WndProc
)(x11
, dlgitem
, event
);
478 std::fprintf(x11
->console
,
479 "window: %s, nWndProc: %d\n", dlgitem
->win
.text
, nWndProc
);
485 if ((dlgitem
->type
== edlgBN
) && (dlgitem
->u
.button
.bDefault
))
489 dlg
->cb(x11
, DLG_EXIT
, dlgitem
->ID
, dlgitem
->win
.text
, dlg
->data
);
498 for (i
= 0; (i
< dlg
->nitem
); i
++)
500 if ((dlg
->dlgitem
[i
]->type
== edlgBN
) &&
501 (dlg
->dlgitem
[i
]->u
.button
.bDefault
))
503 PushMouse(x11
->disp
, dlg
->dlgitem
[i
]->win
.self
,
504 dlg
->dlgitem
[i
]->win
.width
/2,
505 dlg
->dlgitem
[i
]->win
.height
/2);
514 dlg
->cb(x11
, DLG_EXIT
, dlgitem
->ID
, dlgitem
->win
.text
, dlg
->data
);
523 int gid
= dlgitem
->GroupID
;
524 t_id tid
= RBSelected(dlg
, gid
);
526 std::fprintf(stderr
, "RBPRESSED\n");
530 t_dlgitem
*dit
= FindItem(dlg
, tid
);
531 dit
->u
.radiobutton
.bSelect
= false;
532 ExposeWin(x11
->disp
, dit
->win
.self
);
536 gmx_fatal(FARGS
, "No RB Selected initially!\n");
538 dlgitem
->u
.radiobutton
.bSelect
= true;
539 ExposeWin(x11
->disp
, dlgitem
->win
.self
);
542 dlg
->cb(x11
, DLG_SET
, dlgitem
->ID
, dlgitem
->win
.text
, dlg
->data
);
547 ExposeWin(x11
->disp
, dlgitem
->win
.self
);
550 dlg
->cb(x11
, DLG_SET
, dlgitem
->ID
, dlgitem
->set
, dlg
->data
);
554 ExposeWin(x11
->disp
, dlgitem
->win
.self
);
557 dlg
->cb(x11
, DLG_SET
, dlgitem
->ID
, dlgitem
->u
.edittext
.buf
, dlg
->data
);
561 HelpNow(dlg
, dlgitem
);
566 gmx_fatal(FARGS
, "Invalid return code (%d) from wndproc\n", nWndProc
);
569 else if (w
== dlg
->win
.self
)
578 if (HelpPressed(event
))
584 XBell(x11
->disp
, 50);
594 /*****************************
596 * Routine to add an item to the dialog box
597 * The pointer to the item is copied to the dlg struct,
598 * the item itself may not be freed until the dlg is done with
600 ****************************/
601 void DoCreateDlg(t_dlg
*dlg
)
604 XSetWindowAttributes attr
;
607 attr
.border_pixel
= dlg
->x11
->fg
;
608 attr
.background_pixel
= dlg
->bg
;
609 attr
.override_redirect
= False
;
610 attr
.save_under
= True
;
611 attr
.cursor
= XCreateFontCursor(dlg
->x11
->disp
, XC_hand2
);
612 Val
= CWBackPixel
| CWBorderPixel
| CWOverrideRedirect
| CWSaveUnder
|
614 dlg
->win
.self
= XCreateWindow(dlg
->x11
->disp
, dlg
->wDad
,
615 dlg
->win
.x
, dlg
->win
.y
,
616 dlg
->win
.width
, dlg
->win
.height
,
617 dlg
->win
.bwidth
, CopyFromParent
,
618 InputOutput
, CopyFromParent
,
620 dlg
->x11
->RegisterCallback(dlg
->x11
, dlg
->win
.self
, dlg
->wDad
,
622 dlg
->x11
->SetInputMask(dlg
->x11
, dlg
->win
.self
,
623 ExposureMask
| ButtonPressMask
| KeyPressMask
);
625 if (!CheckWindow(dlg
->win
.self
))
629 hints
.x
= dlg
->win
.x
;
630 hints
.y
= dlg
->win
.y
;
631 hints
.flags
= PPosition
;
632 XSetStandardProperties(dlg
->x11
->disp
, dlg
->win
.self
, dlg
->title
,
633 dlg
->title
, None
, nullptr, 0, &hints
);
636 void AddDlgItem(t_dlg
*dlg
, t_dlgitem
*item
)
638 #define EnterLeaveMask (EnterWindowMask | LeaveWindowMask)
639 #define UserMask (ButtonPressMask | KeyPressMask)
640 static unsigned long InputMask
[edlgNR
] = {
641 ExposureMask
| UserMask
| EnterLeaveMask
, /* edlgBN */
642 ExposureMask
| UserMask
| EnterLeaveMask
, /* edlgRB */
643 ExposureMask
, /* edlgGB */
644 ExposureMask
| UserMask
| EnterLeaveMask
, /* edlgCB */
646 ExposureMask
, /* edlgST */
647 ExposureMask
| UserMask
| EnterLeaveMask
/* edlgET */
654 srenew(dlg
->dlgitem
, dlg
->nitem
+1);
657 gmx_fatal(FARGS
, "dlgitem not allocated");
660 XCreateSimpleWindow(dlg
->x11
->disp
, dlg
->win
.self
, item
->win
.x
, item
->win
.y
,
661 item
->win
.width
, item
->win
.height
,
662 item
->win
.bwidth
, dlg
->x11
->fg
, dlg
->x11
->bg
);
663 CheckWindow(item
->win
.self
);
665 dlg
->x11
->RegisterCallback(dlg
->x11
, item
->win
.self
, dlg
->win
.self
,
667 dlg
->x11
->SetInputMask(dlg
->x11
, item
->win
.self
, InputMask
[item
->type
]);
672 XSetWindowBackgroundPixmap(dlg
->x11
->disp
, item
->win
.self
, item
->u
.pixmap
.pm
);
677 dlg
->dlgitem
[dlg
->nitem
] = item
;
682 void AddDlgItems(t_dlg
*dlg
, int nitem
, t_dlgitem
*item
[])
686 for (i
= 0; (i
< nitem
); i
++)
689 std::fprintf(dlg
->x11
->console
,
690 "Adding item: %d from group %d\n", item
[i
]->ID
, item
[i
]->GroupID
);
691 dlg
->x11
->Flush(dlg
->x11
);
693 AddDlgItem(dlg
, item
[i
]);
697 void FreeDlgItem(t_dlg
*dlg
, t_id id
)
702 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
704 dlg
->x11
->UnRegisterCallback(dlg
->x11
, dlgitem
->win
.self
);
705 if (dlgitem
->win
.self
)
707 XDestroyWindow(dlg
->x11
->disp
, dlgitem
->win
.self
);
709 FreeWin(dlg
->x11
->disp
, &(dlgitem
->win
));
710 switch (dlgitem
->type
)
716 sfree(dlgitem
->u
.groupbox
.item
);
721 XFreePixmap(dlg
->x11
->disp
, dlgitem
->u
.pixmap
.pm
);
724 for (i
= 0; (i
< dlgitem
->u
.statictext
.nlines
); i
++)
726 sfree(dlgitem
->u
.statictext
.lines
[i
]);
728 sfree(dlgitem
->u
.statictext
.lines
);
731 sfree(dlgitem
->u
.edittext
.buf
);
739 void FreeDlg(t_dlg
*dlg
)
746 dlg
->x11
->UnRegisterCallback(dlg
->x11
, dlg
->win
.self
);
747 for (i
= 0; (i
< dlg
->nitem
); i
++)
749 FreeDlgItem(dlg
, dlg
->dlgitem
[i
]->ID
);
752 sfree(dlg
->dlgitem
[i
]);
758 XDestroyWindow(dlg
->x11
->disp
, dlg
->win
.self
);
760 dlg
->dlgitem
= nullptr;
764 /*****************************
766 * Routine to create the DLG structure, returns NULL on failure
768 ****************************/
769 t_dlg
*CreateDlg(t_x11
*x11
, Window Parent
, const char *title
,
770 int x0
, int y0
, int w
, int h
, int bw
,
771 DlgCallback
*cb
, void *data
)
782 dlg
->title
= gmx_strdup(title
);
786 dlg
->title
= nullptr;
799 dlg
->xmax
= DisplayWidth(x11
->disp
, x11
->screen
);
800 dlg
->ymax
= DisplayHeight(x11
->disp
, x11
->screen
);
807 XGetGeometry(x11
->disp
, Parent
, &root
, &x
, &y
,
808 &(dlg
->xmax
), &(dlg
->ymax
), &dum
, &dum
);
810 std::fprintf(x11
->console
,
811 "Daddy is %d x %d at %d, %d\n", dlg
->xmax
, dlg
->ymax
, x
, y
);
812 dlg
->x11
->Flush(dlg
->x11
);
823 InitWin(&(dlg
->win
), x
, y
, w
, h
, bw
, nullptr);
824 SetDlgSize(dlg
, w
, h
, x0
|| y0
);
830 dlg
->dlgitem
= nullptr;
836 void SetDlgSize(t_dlg
*dlg
, int w
, int h
, bool bAutoPosition
)
851 std::fprintf(dlg
->x11
->console
, "SetDlgSize: Dialog is %dx%d, at %d,%d\n",
852 dlg
->win
.width
, dlg
->win
.height
, dlg
->win
.x
, dlg
->win
.y
);
853 dlg
->x11
->Flush(dlg
->x11
);
857 XMoveWindow(dlg
->x11
->disp
, dlg
->win
.self
, dlg
->win
.x
, dlg
->win
.y
);
858 XResizeWindow(dlg
->x11
->disp
, dlg
->win
.self
, w
, h
);