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, 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
, "Size window from: %dx%d to %dx%d\n", old_w
, old_h
,
183 dlgitem
->win
.width
, dlgitem
->win
.height
);
184 dlg
->x11
->Flush(dlg
->x11
);
186 if (dlgitem
->win
.self
)
188 XResizeWindow(dlg
->x11
->disp
, dlgitem
->win
.self
, dlgitem
->win
.width
, dlgitem
->win
.height
);
190 if ((w
) && (dlgitem
->type
== edlgGB
))
193 t_id gid
= dlgitem
->GroupID
;
194 t_id id
= dlgitem
->ID
;
195 for (i
= 0; (i
< dlg
->nitem
); i
++)
197 t_dlgitem
* child
= dlg
->dlgitem
[i
];
198 if ((child
->GroupID
== gid
) && (child
->ID
!= id
))
200 SetDlgItemSize(dlg
, child
->ID
, w
- 4 * OFFS_X
, 0);
209 bool SetDlgItemPos(t_dlg
* dlg
, t_id id
, int x0
, int y0
)
214 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
216 old_x
= dlgitem
->win
.x
;
217 old_y
= dlgitem
->win
.y
;
221 std::fprintf(dlg
->x11
->console
, "Move window from: %d,%d to %d,%d\n", old_x
, old_y
, x0
, y0
);
222 dlg
->x11
->Flush(dlg
->x11
);
224 if (dlgitem
->win
.self
)
226 XMoveWindow(dlg
->x11
->disp
, dlgitem
->win
.self
, x0
, y0
);
228 if (dlgitem
->type
== edlgGB
)
231 t_id gid
= dlgitem
->GroupID
;
232 t_id id
= dlgitem
->ID
;
233 x
= dlgitem
->win
.x
+ 2 * OFFS_X
- old_x
;
234 y
= dlgitem
->win
.y
+ 2 * OFFS_Y
- old_y
;
235 for (i
= 0; (i
< dlg
->nitem
); i
++)
237 t_dlgitem
* child
= dlg
->dlgitem
[i
];
238 if ((child
->GroupID
== gid
) && (child
->ID
!= id
))
240 SetDlgItemPos(dlg
, child
->ID
, child
->win
.x
+ x
, child
->win
.y
+ y
);
249 /*****************************
251 * Routines to extract information from the dlg proc
252 * after dlg is exec'ed
254 ****************************/
255 bool IsCBChecked(t_dlg
* dlg
, t_id id
)
259 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
261 if (dlgitem
->type
== edlgCB
)
263 return dlgitem
->u
.checkbox
.bChecked
;
270 t_id
RBSelected(t_dlg
* dlg
, int gid
)
274 for (i
= 0; (i
< dlg
->nitem
); i
++)
276 if ((dlg
->dlgitem
[i
]->type
== edlgRB
) && (dlg
->dlgitem
[i
]->u
.radiobutton
.bSelect
)
277 && (dlg
->dlgitem
[i
]->GroupID
== gid
))
279 return dlg
->dlgitem
[i
]->ID
;
286 int EditTextLen(t_dlg
* dlg
, t_id id
)
290 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
292 if (dlgitem
->type
== edlgET
)
294 return std::strlen(dlgitem
->u
.edittext
.buf
);
301 char* EditText(t_dlg
* dlg
, t_id id
)
305 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
307 if (dlgitem
->type
== edlgET
)
309 return dlgitem
->u
.edittext
.buf
;
316 /*****************************
318 * Exececute the dialog box procedure
319 * Returns when a button is pushed.
320 * return value is the ID of the button
322 ****************************/
323 void ShowDlg(t_dlg
* dlg
)
328 XMapWindow(dlg
->x11
->disp
, dlg
->win
.self
);
329 XMapSubwindows(dlg
->x11
->disp
, dlg
->win
.self
);
330 for (i
= 0; (i
< dlg
->nitem
); i
++)
332 LightBorder(dlg
->x11
->disp
, dlg
->dlgitem
[i
]->win
.self
, dlg
->bg
);
334 XSetForeground(dlg
->x11
->disp
, dlg
->x11
->gc
, dlg
->x11
->fg
);
335 for (i
= 0; (i
< dlg
->nitem
); i
++)
337 dlgitem
= dlg
->dlgitem
[i
];
338 if ((dlgitem
->type
== edlgBN
) && (dlgitem
->u
.button
.bDefault
))
340 PushMouse(dlg
->x11
->disp
, dlgitem
->win
.self
, dlgitem
->win
.width
/ 2, dlgitem
->win
.height
/ 2);
348 void HideDlg(t_dlg
* dlg
)
352 PopMouse(dlg
->x11
->disp
);
355 XUnmapSubwindows(dlg
->x11
->disp
, dlg
->win
.self
);
356 XUnmapWindow(dlg
->x11
->disp
, dlg
->win
.self
);
359 void NoHelp(t_dlg
* dlg
)
361 const char* lines
[2] = { "Error", "No help for this item" };
362 MessageBox(dlg
->x11
, dlg
->wDad
, "No Help", 2, lines
, MB_OK
| MB_ICONSTOP
| MB_APPLMODAL
,
366 void HelpDlg(t_dlg
* dlg
)
368 const char* lines
[] = { "Place the cursor over one of the items",
369 "and press the F1 key to get more help.", "First press the OK button." };
370 MessageBox(dlg
->x11
, dlg
->win
.self
, "Help Dialogbox", 3, lines
,
371 MB_OK
| MB_ICONINFORMATION
| MB_APPLMODAL
, nullptr, nullptr);
374 void HelpNow(t_dlg
* dlg
, t_dlgitem
* dlgitem
)
379 char** lines
= nullptr;
387 std::printf("%s\n", dlgitem
->help
);
390 fgets2(buf
, 79, stdin
);
392 std::fprintf(dlg
->x11
->console
, "buffer: '%s'\n", buf
);
393 dlg
->x11
->Flush(dlg
->x11
);
395 if (gmx_strcasecmp(buf
, "nok") == 0)
397 /* An error occurred */
400 for (i
= 0; (i
< nlines
); i
++)
411 bCont
= (gmx_strcasecmp(buf
, "ok") != 0);
414 srenew(lines
, ++nlines
);
415 lines
[nlines
- 1] = gmx_strdup(buf
);
419 MessageBox(dlg
->x11
, dlg
->wDad
, "Help", nlines
, lines
,
420 MB_OK
| MB_ICONINFORMATION
| MB_APPLMODAL
, nullptr, nullptr);
421 for (i
= 0; (i
< nlines
); i
++)
428 static void EnterDlg(t_dlg
* dlg
)
430 if (dlg
->flags
& DLG_APPLMODAL
)
432 dlg
->bGrab
= GrabOK(dlg
->x11
->console
,
433 XGrabPointer(dlg
->x11
->disp
, dlg
->win
.self
, True
, 0, GrabModeAsync
,
434 GrabModeAsync
, dlg
->win
.self
, None
, CurrentTime
));
436 dlg
->x11
->Flush(dlg
->x11
);
439 static void ExitDlg(t_dlg
* dlg
)
443 XUngrabPointer(dlg
->x11
->disp
, CurrentTime
);
447 if (dlg
->flags
& DLG_FREEONBUTTON
)
453 static bool DlgCB(t_x11
* x11
, XEvent
* event
, Window w
, void* data
)
455 t_dlg
* dlg
= (t_dlg
*)data
;
459 if ((dlgitem
= FindWin(dlg
, w
)) != nullptr)
461 nWndProc
= (dlgitem
->WndProc
)(x11
, dlgitem
, event
);
463 std::fprintf(x11
->console
, "window: %s, nWndProc: %d\n", dlgitem
->win
.text
, nWndProc
);
469 if ((dlgitem
->type
== edlgBN
) && (dlgitem
->u
.button
.bDefault
))
473 dlg
->cb(x11
, DLG_EXIT
, dlgitem
->ID
, dlgitem
->win
.text
, dlg
->data
);
482 for (i
= 0; (i
< dlg
->nitem
); i
++)
484 if ((dlg
->dlgitem
[i
]->type
== edlgBN
) && (dlg
->dlgitem
[i
]->u
.button
.bDefault
))
486 PushMouse(x11
->disp
, dlg
->dlgitem
[i
]->win
.self
,
487 dlg
->dlgitem
[i
]->win
.width
/ 2, dlg
->dlgitem
[i
]->win
.height
/ 2);
496 dlg
->cb(x11
, DLG_EXIT
, dlgitem
->ID
, dlgitem
->win
.text
, dlg
->data
);
505 int gid
= dlgitem
->GroupID
;
506 t_id tid
= RBSelected(dlg
, gid
);
508 std::fprintf(stderr
, "RBPRESSED\n");
512 t_dlgitem
* dit
= FindItem(dlg
, tid
);
513 dit
->u
.radiobutton
.bSelect
= false;
514 ExposeWin(x11
->disp
, dit
->win
.self
);
518 gmx_fatal(FARGS
, "No RB Selected initially!\n");
520 dlgitem
->u
.radiobutton
.bSelect
= true;
521 ExposeWin(x11
->disp
, dlgitem
->win
.self
);
524 dlg
->cb(x11
, DLG_SET
, dlgitem
->ID
, dlgitem
->win
.text
, dlg
->data
);
529 ExposeWin(x11
->disp
, dlgitem
->win
.self
);
532 dlg
->cb(x11
, DLG_SET
, dlgitem
->ID
, dlgitem
->set
, dlg
->data
);
536 ExposeWin(x11
->disp
, dlgitem
->win
.self
);
539 dlg
->cb(x11
, DLG_SET
, dlgitem
->ID
, dlgitem
->u
.edittext
.buf
, dlg
->data
);
542 case HELPPRESSED
: HelpNow(dlg
, dlgitem
); break;
544 default: gmx_fatal(FARGS
, "Invalid return code (%d) from wndproc\n", nWndProc
);
547 else if (w
== dlg
->win
.self
)
551 case Expose
: EnterDlg(dlg
); break;
554 if (HelpPressed(event
))
560 XBell(x11
->disp
, 50);
569 /*****************************
571 * Routine to add an item to the dialog box
572 * The pointer to the item is copied to the dlg struct,
573 * the item itself may not be freed until the dlg is done with
575 ****************************/
576 static void DoCreateDlg(t_dlg
* dlg
)
579 XSetWindowAttributes attr
;
582 attr
.border_pixel
= dlg
->x11
->fg
;
583 attr
.background_pixel
= dlg
->bg
;
584 attr
.override_redirect
= False
;
585 attr
.save_under
= True
;
586 attr
.cursor
= XCreateFontCursor(dlg
->x11
->disp
, XC_hand2
);
587 Val
= CWBackPixel
| CWBorderPixel
| CWOverrideRedirect
| CWSaveUnder
| CWCursor
;
588 dlg
->win
.self
= XCreateWindow(dlg
->x11
->disp
, dlg
->wDad
, dlg
->win
.x
, dlg
->win
.y
, dlg
->win
.width
,
589 dlg
->win
.height
, dlg
->win
.bwidth
, CopyFromParent
, InputOutput
,
590 CopyFromParent
, Val
, &attr
);
591 dlg
->x11
->RegisterCallback(dlg
->x11
, dlg
->win
.self
, dlg
->wDad
, DlgCB
, dlg
);
592 dlg
->x11
->SetInputMask(dlg
->x11
, dlg
->win
.self
, ExposureMask
| ButtonPressMask
| KeyPressMask
);
594 if (!CheckWindow(dlg
->win
.self
))
598 hints
.x
= dlg
->win
.x
;
599 hints
.y
= dlg
->win
.y
;
600 hints
.flags
= PPosition
;
601 XSetStandardProperties(dlg
->x11
->disp
, dlg
->win
.self
, dlg
->title
, dlg
->title
, None
, nullptr, 0, &hints
);
604 void AddDlgItem(t_dlg
* dlg
, t_dlgitem
* item
)
606 #define EnterLeaveMask (EnterWindowMask | LeaveWindowMask)
607 #define UserMask (ButtonPressMask | KeyPressMask)
608 static unsigned long InputMask
[edlgNR
] = {
609 ExposureMask
| UserMask
| EnterLeaveMask
, /* edlgBN */
610 ExposureMask
| UserMask
| EnterLeaveMask
, /* edlgRB */
611 ExposureMask
, /* edlgGB */
612 ExposureMask
| UserMask
| EnterLeaveMask
, /* edlgCB */
614 ExposureMask
, /* edlgST */
615 ExposureMask
| UserMask
| EnterLeaveMask
/* edlgET */
622 srenew(dlg
->dlgitem
, dlg
->nitem
+ 1);
625 gmx_fatal(FARGS
, "dlgitem not allocated");
627 item
->win
.self
= XCreateSimpleWindow(dlg
->x11
->disp
, dlg
->win
.self
, item
->win
.x
, item
->win
.y
,
628 item
->win
.width
, item
->win
.height
, item
->win
.bwidth
,
629 dlg
->x11
->fg
, dlg
->x11
->bg
);
630 CheckWindow(item
->win
.self
);
632 dlg
->x11
->RegisterCallback(dlg
->x11
, item
->win
.self
, dlg
->win
.self
, DlgCB
, dlg
);
633 dlg
->x11
->SetInputMask(dlg
->x11
, item
->win
.self
, InputMask
[item
->type
]);
638 XSetWindowBackgroundPixmap(dlg
->x11
->disp
, item
->win
.self
, item
->u
.pixmap
.pm
);
642 dlg
->dlgitem
[dlg
->nitem
] = item
;
647 void AddDlgItems(t_dlg
* dlg
, int nitem
, t_dlgitem
* item
[])
651 for (i
= 0; (i
< nitem
); i
++)
654 std::fprintf(dlg
->x11
->console
, "Adding item: %d from group %d\n", item
[i
]->ID
, item
[i
]->GroupID
);
655 dlg
->x11
->Flush(dlg
->x11
);
657 AddDlgItem(dlg
, item
[i
]);
661 void FreeDlgItem(t_dlg
* dlg
, t_id id
)
666 if ((dlgitem
= FindItem(dlg
, id
)) != nullptr)
668 dlg
->x11
->UnRegisterCallback(dlg
->x11
, dlgitem
->win
.self
);
669 if (dlgitem
->win
.self
)
671 XDestroyWindow(dlg
->x11
->disp
, dlgitem
->win
.self
);
673 FreeWin(dlg
->x11
->disp
, &(dlgitem
->win
));
674 switch (dlgitem
->type
)
678 case edlgGB
: sfree(dlgitem
->u
.groupbox
.item
); break;
680 case edlgPM
: XFreePixmap(dlg
->x11
->disp
, dlgitem
->u
.pixmap
.pm
); break;
682 for (i
= 0; (i
< dlgitem
->u
.statictext
.nlines
); i
++)
684 sfree(dlgitem
->u
.statictext
.lines
[i
]);
686 sfree(dlgitem
->u
.statictext
.lines
);
688 case edlgET
: sfree(dlgitem
->u
.edittext
.buf
); break;
694 void FreeDlg(t_dlg
* dlg
)
701 dlg
->x11
->UnRegisterCallback(dlg
->x11
, dlg
->win
.self
);
702 for (i
= 0; (i
< dlg
->nitem
); i
++)
704 FreeDlgItem(dlg
, dlg
->dlgitem
[i
]->ID
);
707 sfree(dlg
->dlgitem
[i
]);
713 XDestroyWindow(dlg
->x11
->disp
, dlg
->win
.self
);
715 dlg
->dlgitem
= nullptr;
719 /*****************************
721 * Routine to create the DLG structure, returns NULL on failure
723 ****************************/
724 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
)
735 dlg
->title
= gmx_strdup(title
);
739 dlg
->title
= nullptr;
752 dlg
->xmax
= DisplayWidth(x11
->disp
, x11
->screen
);
753 dlg
->ymax
= DisplayHeight(x11
->disp
, x11
->screen
);
760 XGetGeometry(x11
->disp
, Parent
, &root
, &x
, &y
, &(dlg
->xmax
), &(dlg
->ymax
), &dum
, &dum
);
762 std::fprintf(x11
->console
, "Daddy is %d x %d at %d, %d\n", dlg
->xmax
, dlg
->ymax
, x
, y
);
763 dlg
->x11
->Flush(dlg
->x11
);
774 InitWin(&(dlg
->win
), x
, y
, w
, h
, bw
, nullptr);
775 SetDlgSize(dlg
, w
, h
, x0
|| y0
);
781 dlg
->dlgitem
= nullptr;
787 void SetDlgSize(t_dlg
* dlg
, int w
, int h
, bool bAutoPosition
)
793 x
= (dlg
->xmax
- w
) / 2;
794 y
= (dlg
->ymax
- h
) / 2;
802 std::fprintf(dlg
->x11
->console
, "SetDlgSize: Dialog is %dx%d, at %d,%d\n", dlg
->win
.width
,
803 dlg
->win
.height
, dlg
->win
.x
, dlg
->win
.y
);
804 dlg
->x11
->Flush(dlg
->x11
);
808 XMoveWindow(dlg
->x11
->disp
, dlg
->win
.self
, dlg
->win
.x
, dlg
->win
.y
);
809 XResizeWindow(dlg
->x11
->disp
, dlg
->win
.self
, w
, h
);