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,2019,2020, 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",
187 dlgitem->win.height);
188 dlg->x11->Flush(dlg->x11);
190 if (dlgitem->win.self)
192 XResizeWindow(dlg->x11->disp, dlgitem->win.self, dlgitem->win.width, dlgitem->win.height);
194 if ((w) && (dlgitem->type == edlgGB))
197 t_id gid = dlgitem->GroupID;
198 t_id id = dlgitem->ID;
199 for (i = 0; (i < dlg->nitem); i++)
201 t_dlgitem* child = dlg->dlgitem[i];
202 if ((child->GroupID == gid) && (child->ID != id))
204 SetDlgItemSize(dlg, child->ID, w - 4 * OFFS_X, 0);
213 bool SetDlgItemPos(t_dlg* dlg, t_id id, int x0, int y0)
218 if ((dlgitem = FindItem(dlg, id)) != nullptr)
220 old_x = dlgitem->win.x;
221 old_y = dlgitem->win.y;
225 std::fprintf(dlg->x11->console, "Move window from: %d,%d to %d,%d\n", old_x, old_y, x0, y0);
226 dlg->x11->Flush(dlg->x11);
228 if (dlgitem->win.self)
230 XMoveWindow(dlg->x11->disp, dlgitem->win.self, x0, y0);
232 if (dlgitem->type == edlgGB)
235 t_id gid = dlgitem->GroupID;
236 t_id id = dlgitem->ID;
237 x = dlgitem->win.x + 2 * OFFS_X - old_x;
238 y = dlgitem->win.y + 2 * OFFS_Y - old_y;
239 for (i = 0; (i < dlg->nitem); i++)
241 t_dlgitem* child = dlg->dlgitem[i];
242 if ((child->GroupID == gid) && (child->ID != id))
244 SetDlgItemPos(dlg, child->ID, child->win.x + x, child->win.y + y);
253 /*****************************
255 * Routines to extract information from the dlg proc
256 * after dlg is exec'ed
258 ****************************/
259 bool IsCBChecked(t_dlg* dlg, t_id id)
263 if ((dlgitem = FindItem(dlg, id)) != nullptr)
265 if (dlgitem->type == edlgCB)
267 return dlgitem->u.checkbox.bChecked;
274 t_id RBSelected(t_dlg* dlg, int gid)
278 for (i = 0; (i < dlg->nitem); i++)
280 if ((dlg->dlgitem[i]->type == edlgRB) && (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) && (dlgitem->u.button.bDefault))
344 PushMouse(dlg->x11->disp, dlgitem->win.self, dlgitem->win.width / 2, dlgitem->win.height / 2);
352 void HideDlg(t_dlg* dlg)
356 PopMouse(dlg->x11->disp);
359 XUnmapSubwindows(dlg->x11->disp, dlg->win.self);
360 XUnmapWindow(dlg->x11->disp, dlg->win.self);
363 void NoHelp(t_dlg* dlg)
365 const char* lines[2] = { "Error", "No help for this item" };
366 MessageBox(dlg->x11, dlg->wDad, "No Help", 2, lines, MB_OK | MB_ICONSTOP | MB_APPLMODAL, nullptr, nullptr);
369 void HelpDlg(t_dlg* dlg)
371 const char* lines[] = { "Place the cursor over one of the items",
372 "and press the F1 key to get more help.",
373 "First press the OK button." };
374 MessageBox(dlg->x11, dlg->win.self, "Help Dialogbox", 3, lines, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, nullptr, nullptr);
377 void HelpNow(t_dlg* dlg, t_dlgitem* dlgitem)
382 char** lines = nullptr;
390 std::printf("%s\n", dlgitem->help);
393 fgets2(buf, 79, stdin);
395 std::fprintf(dlg->x11->console, "buffer: '%s'\n", buf);
396 dlg->x11->Flush(dlg->x11);
398 if (gmx_strcasecmp(buf, "nok") == 0)
400 /* An error occurred */
403 for (i = 0; (i < nlines); i++)
414 bCont = (gmx_strcasecmp(buf, "ok") != 0);
417 srenew(lines, ++nlines);
418 lines[nlines - 1] = gmx_strdup(buf);
422 MessageBox(dlg->x11, dlg->wDad, "Help", nlines, lines, MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, nullptr, nullptr);
423 for (i = 0; (i < nlines); i++)
430 static void EnterDlg(t_dlg* dlg)
432 if (dlg->flags & DLG_APPLMODAL)
437 dlg->x11->disp, dlg->win.self, True, 0, GrabModeAsync, GrabModeAsync, dlg->win.self, None, CurrentTime));
439 dlg->x11->Flush(dlg->x11);
442 static void ExitDlg(t_dlg* dlg)
446 XUngrabPointer(dlg->x11->disp, CurrentTime);
450 if (dlg->flags & DLG_FREEONBUTTON)
456 static bool DlgCB(t_x11* x11, XEvent* event, Window w, void* data)
458 t_dlg* dlg = (t_dlg*)data;
462 if ((dlgitem = FindWin(dlg, w)) != nullptr)
464 nWndProc = (dlgitem->WndProc)(x11, dlgitem, event);
466 std::fprintf(x11->console, "window: %s, nWndProc: %d\n", dlgitem->win.text, nWndProc);
472 if ((dlgitem->type == edlgBN) && (dlgitem->u.button.bDefault))
476 dlg->cb(x11, DLG_EXIT, dlgitem->ID, dlgitem->win.text, dlg->data);
485 for (i = 0; (i < dlg->nitem); i++)
487 if ((dlg->dlgitem[i]->type == edlgBN) && (dlg->dlgitem[i]->u.button.bDefault))
490 dlg->dlgitem[i]->win.self,
491 dlg->dlgitem[i]->win.width / 2,
492 dlg->dlgitem[i]->win.height / 2);
501 dlg->cb(x11, DLG_EXIT, dlgitem->ID, dlgitem->win.text, dlg->data);
510 int gid = dlgitem->GroupID;
511 t_id tid = RBSelected(dlg, gid);
513 std::fprintf(stderr, "RBPRESSED\n");
517 t_dlgitem* dit = FindItem(dlg, tid);
518 dit->u.radiobutton.bSelect = false;
519 ExposeWin(x11->disp, dit->win.self);
523 gmx_fatal(FARGS, "No RB Selected initially!\n");
525 dlgitem->u.radiobutton.bSelect = true;
526 ExposeWin(x11->disp, dlgitem->win.self);
529 dlg->cb(x11, DLG_SET, dlgitem->ID, dlgitem->win.text, dlg->data);
534 ExposeWin(x11->disp, dlgitem->win.self);
537 dlg->cb(x11, DLG_SET, dlgitem->ID, dlgitem->set, dlg->data);
541 ExposeWin(x11->disp, dlgitem->win.self);
544 dlg->cb(x11, DLG_SET, dlgitem->ID, dlgitem->u.edittext.buf, dlg->data);
547 case HELPPRESSED: HelpNow(dlg, dlgitem); break;
549 default: gmx_fatal(FARGS, "Invalid return code (%d) from wndproc\n", nWndProc);
552 else if (w == dlg->win.self)
556 case Expose: EnterDlg(dlg); break;
559 if (HelpPressed(event))
565 XBell(x11->disp, 50);
574 /*****************************
576 * Routine to add an item to the dialog box
577 * The pointer to the item is copied to the dlg struct,
578 * the item itself may not be freed until the dlg is done with
580 ****************************/
581 static void DoCreateDlg(t_dlg* dlg)
584 XSetWindowAttributes attr;
587 attr.border_pixel = dlg->x11->fg;
588 attr.background_pixel = dlg->bg;
589 attr.override_redirect = False;
590 attr.save_under = True;
591 attr.cursor = XCreateFontCursor(dlg->x11->disp, XC_hand2);
592 Val = CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWSaveUnder | CWCursor;
593 dlg->win.self = XCreateWindow(dlg->x11->disp,
605 dlg->x11->RegisterCallback(dlg->x11, dlg->win.self, dlg->wDad, DlgCB, dlg);
606 dlg->x11->SetInputMask(dlg->x11, dlg->win.self, ExposureMask | ButtonPressMask | KeyPressMask);
608 if (!CheckWindow(dlg->win.self))
612 hints.x = dlg->win.x;
613 hints.y = dlg->win.y;
614 hints.flags = PPosition;
615 XSetStandardProperties(dlg->x11->disp, dlg->win.self, dlg->title, dlg->title, None, nullptr, 0, &hints);
618 void AddDlgItem(t_dlg* dlg, t_dlgitem* item)
620 #define EnterLeaveMask (EnterWindowMask | LeaveWindowMask)
621 #define UserMask (ButtonPressMask | KeyPressMask)
622 static unsigned long InputMask[edlgNR] = {
623 ExposureMask | UserMask | EnterLeaveMask, /* edlgBN */
624 ExposureMask | UserMask | EnterLeaveMask, /* edlgRB */
625 ExposureMask, /* edlgGB */
626 ExposureMask | UserMask | EnterLeaveMask, /* edlgCB */
628 ExposureMask, /* edlgST */
629 ExposureMask | UserMask | EnterLeaveMask /* edlgET */
636 srenew(dlg->dlgitem, dlg->nitem + 1);
639 gmx_fatal(FARGS, "dlgitem not allocated");
641 item->win.self = XCreateSimpleWindow(dlg->x11->disp,
650 CheckWindow(item->win.self);
652 dlg->x11->RegisterCallback(dlg->x11, item->win.self, dlg->win.self, DlgCB, dlg);
653 dlg->x11->SetInputMask(dlg->x11, item->win.self, InputMask[item->type]);
658 XSetWindowBackgroundPixmap(dlg->x11->disp, item->win.self, item->u.pixmap.pm);
662 dlg->dlgitem[dlg->nitem] = item;
667 void AddDlgItems(t_dlg* dlg, int nitem, t_dlgitem* item[])
671 for (i = 0; (i < nitem); i++)
674 std::fprintf(dlg->x11->console, "Adding item: %d from group %d\n", item[i]->ID, item[i]->GroupID);
675 dlg->x11->Flush(dlg->x11);
677 AddDlgItem(dlg, item[i]);
681 void FreeDlgItem(t_dlg* dlg, t_id id)
686 if ((dlgitem = FindItem(dlg, id)) != nullptr)
688 dlg->x11->UnRegisterCallback(dlg->x11, dlgitem->win.self);
689 if (dlgitem->win.self)
691 XDestroyWindow(dlg->x11->disp, dlgitem->win.self);
693 FreeWin(dlg->x11->disp, &(dlgitem->win));
694 switch (dlgitem->type)
698 case edlgGB: sfree(dlgitem->u.groupbox.item); break;
700 case edlgPM: XFreePixmap(dlg->x11->disp, dlgitem->u.pixmap.pm); break;
702 for (i = 0; (i < dlgitem->u.statictext.nlines); i++)
704 sfree(dlgitem->u.statictext.lines[i]);
706 sfree(dlgitem->u.statictext.lines);
708 case edlgET: sfree(dlgitem->u.edittext.buf); break;
714 void FreeDlg(t_dlg* dlg)
721 dlg->x11->UnRegisterCallback(dlg->x11, dlg->win.self);
722 for (i = 0; (i < dlg->nitem); i++)
724 FreeDlgItem(dlg, dlg->dlgitem[i]->ID);
727 sfree(dlg->dlgitem[i]);
733 XDestroyWindow(dlg->x11->disp, dlg->win.self);
735 dlg->dlgitem = nullptr;
739 /*****************************
741 * Routine to create the DLG structure, returns NULL on failure
743 ****************************/
744 t_dlg* CreateDlg(t_x11* x11, Window Parent, const char* title, int x0, int y0, int w, int h, int bw, DlgCallback* cb, void* data)
755 dlg->title = gmx_strdup(title);
759 dlg->title = nullptr;
772 dlg->xmax = DisplayWidth(x11->disp, x11->screen);
773 dlg->ymax = DisplayHeight(x11->disp, x11->screen);
780 XGetGeometry(x11->disp, Parent, &root, &x, &y, &(dlg->xmax), &(dlg->ymax), &dum, &dum);
782 std::fprintf(x11->console, "Daddy is %d x %d at %d, %d\n", dlg->xmax, dlg->ymax, x, y);
783 dlg->x11->Flush(dlg->x11);
794 InitWin(&(dlg->win), x, y, w, h, bw, nullptr);
795 SetDlgSize(dlg, w, h, x0 || y0);
801 dlg->dlgitem = nullptr;
807 void SetDlgSize(t_dlg* dlg, int w, int h, bool bAutoPosition)
813 x = (dlg->xmax - w) / 2;
814 y = (dlg->ymax - h) / 2;
822 std::fprintf(dlg->x11->console,
823 "SetDlgSize: Dialog is %dx%d, at %d,%d\n",
828 dlg->x11->Flush(dlg->x11);
832 XMoveWindow(dlg->x11->disp, dlg->win.self, dlg->win.x, dlg->win.y);
833 XResizeWindow(dlg->x11->disp, dlg->win.self, w, h);