Tidy: modernize-use-nullptr
[gromacs.git] / src / programs / view / xdlg.cpp
blob230623820727904de9d1595033797b821f1c454b
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 * 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.
37 #include "gmxpre.h"
39 #include "xdlg.h"
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
45 #include "gromacs/utility/cstringutil.h"
46 #include "gromacs/utility/fatalerror.h"
47 #include "gromacs/utility/smalloc.h"
49 #include "Xstuff.h"
50 #include "xmb.h"
51 #include "xutil.h"
52 /*****************************
54 * Helpful routines
56 ****************************/
57 t_dlgitem *FindItem(t_dlg *dlg, t_id id)
59 int i;
61 for (i = 0; (i < dlg->nitem); i++)
63 if (dlg->dlgitem[i]->ID == id)
65 return dlg->dlgitem[i];
68 return nullptr;
71 t_dlgitem *FindWin(t_dlg *dlg, Window win)
73 int i;
75 for (i = 0; (i < dlg->nitem); i++)
77 if (dlg->dlgitem[i]->win.self == win)
79 return dlg->dlgitem[i];
82 return nullptr;
85 /*****************************
87 * Routines to manipulate items on a dialog box
89 ****************************/
90 bool QueryDlgItemSize(t_dlg *dlg, t_id id, int *w, int *h)
92 t_dlgitem *dlgitem;
94 if ((dlgitem = FindItem(dlg, id)) != nullptr)
96 *w = dlgitem->win.width;
97 *h = dlgitem->win.height;
98 return true;
100 return false;
103 bool QueryDlgItemPos(t_dlg *dlg, t_id id, int *x0, int *y0)
105 t_dlgitem *dlgitem;
107 if ((dlgitem = FindItem(dlg, id)) != nullptr)
109 *x0 = dlgitem->win.x;
110 *y0 = dlgitem->win.y;
111 return true;
113 return false;
116 int QueryDlgItemX(t_dlg *dlg, t_id id)
118 t_dlgitem *dlgitem;
120 if ((dlgitem = FindItem(dlg, id)) != nullptr)
122 return dlgitem->win.x;
124 return 0;
127 int QueryDlgItemY(t_dlg *dlg, t_id id)
129 t_dlgitem *dlgitem;
131 if ((dlgitem = FindItem(dlg, id)) != nullptr)
133 return dlgitem->win.y;
135 return 0;
138 int QueryDlgItemW(t_dlg *dlg, t_id id)
140 t_dlgitem *dlgitem;
142 if ((dlgitem = FindItem(dlg, id)) != nullptr)
144 return dlgitem->win.width;
146 return 0;
149 int QueryDlgItemH(t_dlg *dlg, t_id id)
151 t_dlgitem *dlgitem;
153 if ((dlgitem = FindItem(dlg, id)) != nullptr)
155 return dlgitem->win.height;
157 return 0;
160 bool SetDlgItemSize(t_dlg *dlg, t_id id, int w, int h)
162 t_dlgitem *dlgitem;
163 #ifdef DEBUG
164 int old_w, old_h;
165 #endif
167 if ((dlgitem = FindItem(dlg, id)) != nullptr)
169 #ifdef DEBUG
170 old_w = dlgitem->win.width;
171 old_h = dlgitem->win.height;
172 #endif
173 if (w)
175 dlgitem->win.width = w;
177 if (h)
179 dlgitem->win.height = h;
181 #ifdef DEBUG
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);
186 #endif
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))
194 int i;
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);
206 return true;
208 return false;
211 bool SetDlgItemPos(t_dlg *dlg, t_id id, int x0, int y0)
213 t_dlgitem *dlgitem;
214 int old_x, old_y;
216 if ((dlgitem = FindItem(dlg, id)) != nullptr)
218 old_x = dlgitem->win.x;
219 old_y = dlgitem->win.y;
220 dlgitem->win.x = x0;
221 dlgitem->win.y = y0;
222 #ifdef DEBUG
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);
226 #endif
227 if (dlgitem->win.self)
229 XMoveWindow(dlg->x11->disp, dlgitem->win.self, x0, y0);
231 if (dlgitem->type == edlgGB)
233 int i, x, y;
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);
247 return true;
249 return false;
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)
260 t_dlgitem *dlgitem;
262 if ((dlgitem = FindItem(dlg, id)) != nullptr)
264 if (dlgitem->type == edlgCB)
266 return dlgitem->u.checkbox.bChecked;
270 return false;
273 t_id RBSelected(t_dlg *dlg, int gid)
275 int i;
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;
287 return -1;
290 int EditTextLen(t_dlg *dlg, t_id id)
292 t_dlgitem *dlgitem;
294 if ((dlgitem = FindItem(dlg, id)) != nullptr)
296 if (dlgitem->type == edlgET)
298 return std::strlen(dlgitem->u.edittext.buf);
302 return 0;
305 char *EditText(t_dlg *dlg, t_id id)
307 t_dlgitem *dlgitem;
309 if ((dlgitem = FindItem(dlg, id)) != nullptr)
311 if (dlgitem->type == edlgET)
313 return dlgitem->u.edittext.buf;
317 return nullptr;
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)
329 int i;
330 t_dlgitem *dlgitem;
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);
347 dlg->bPop = true;
348 break;
351 dlg->bGrab = false;
354 void HideDlg(t_dlg *dlg)
356 if (dlg->bPop)
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] = {
368 "Error",
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)
388 char buf[80];
389 bool bCont = true;
390 int i, nlines = 0;
391 char **lines = nullptr;
393 if (!dlgitem->help)
395 NoHelp(dlg);
396 return;
399 std::printf("%s\n", dlgitem->help);
402 fgets2(buf, 79, stdin);
403 #ifdef DEBUG
404 std::fprintf(dlg->x11->console, "buffer: '%s'\n", buf);
405 dlg->x11->Flush(dlg->x11);
406 #endif
407 if (gmx_strcasecmp(buf, "nok") == 0)
409 /* An error occurred */
410 if (lines)
412 for (i = 0; (i < nlines); i++)
414 sfree(lines[i]);
416 sfree(lines);
418 NoHelp(dlg);
419 return;
421 else
423 bCont = (gmx_strcasecmp(buf, "ok") != 0);
424 if (bCont)
426 srenew(lines, ++nlines);
427 lines[nlines-1] = gmx_strdup(buf);
431 while (bCont);
432 MessageBox(dlg->x11, dlg->wDad, "Help",
433 nlines, lines,
434 MB_OK | MB_ICONINFORMATION | MB_APPLMODAL, nullptr, nullptr);
435 for (i = 0; (i < nlines); i++)
437 sfree(lines[i]);
439 sfree(lines);
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)
456 if (dlg->bGrab)
458 XUngrabPointer(dlg->x11->disp, CurrentTime);
459 dlg->bGrab = false;
461 HideDlg(dlg);
462 if (dlg->flags & DLG_FREEONBUTTON)
464 FreeDlg(dlg);
468 static bool DlgCB(t_x11 *x11, XEvent *event, Window w, void *data)
470 t_dlg *dlg = (t_dlg *)data;
471 int i, nWndProc;
472 t_dlgitem *dlgitem;
474 if ((dlgitem = FindWin(dlg, w)) != nullptr)
476 nWndProc = (dlgitem->WndProc)(x11, dlgitem, event);
477 #ifdef DEBUG
478 std::fprintf(x11->console,
479 "window: %s, nWndProc: %d\n", dlgitem->win.text, nWndProc);
480 x11->Flush(x11);
481 #endif
482 switch (nWndProc)
484 case ENTERPRESSED:
485 if ((dlgitem->type == edlgBN) && (dlgitem->u.button.bDefault))
487 if (dlg->cb)
489 dlg->cb(x11, DLG_EXIT, dlgitem->ID, dlgitem->win.text, dlg->data);
491 else
493 ExitDlg(dlg);
496 else
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);
506 break;
510 break;
511 case BNPRESSED:
512 if (dlg->cb)
514 dlg->cb(x11, DLG_EXIT, dlgitem->ID, dlgitem->win.text, dlg->data);
516 else
518 ExitDlg(dlg);
520 break;
521 case RBPRESSED:
523 int gid = dlgitem->GroupID;
524 t_id tid = RBSelected(dlg, gid);
525 #ifdef DEBUG
526 std::fprintf(stderr, "RBPRESSED\n");
527 #endif
528 if (tid != -1)
530 t_dlgitem *dit = FindItem(dlg, tid);
531 dit->u.radiobutton.bSelect = false;
532 ExposeWin(x11->disp, dit->win.self);
534 else
536 gmx_fatal(FARGS, "No RB Selected initially!\n");
538 dlgitem->u.radiobutton.bSelect = true;
539 ExposeWin(x11->disp, dlgitem->win.self);
540 if (dlg->cb)
542 dlg->cb(x11, DLG_SET, dlgitem->ID, dlgitem->win.text, dlg->data);
544 break;
546 case CBPRESSED:
547 ExposeWin(x11->disp, dlgitem->win.self);
548 if (dlg->cb)
550 dlg->cb(x11, DLG_SET, dlgitem->ID, dlgitem->set, dlg->data);
552 break;
553 case ETCHANGED:
554 ExposeWin(x11->disp, dlgitem->win.self);
555 if (dlg->cb)
557 dlg->cb(x11, DLG_SET, dlgitem->ID, dlgitem->u.edittext.buf, dlg->data);
559 break;
560 case HELPPRESSED:
561 HelpNow(dlg, dlgitem);
562 break;
563 case ITEMOK:
564 break;
565 default:
566 gmx_fatal(FARGS, "Invalid return code (%d) from wndproc\n", nWndProc);
569 else if (w == dlg->win.self)
571 switch (event->type)
573 case Expose:
574 EnterDlg(dlg);
575 break;
576 case ButtonPress:
577 case KeyPress:
578 if (HelpPressed(event))
580 HelpDlg(dlg);
582 else
584 XBell(x11->disp, 50);
586 break;
587 default:
588 break;
591 return false;
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)
603 XSizeHints hints;
604 XSetWindowAttributes attr;
605 unsigned long Val;
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 |
613 CWCursor;
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,
619 Val, &attr);
620 dlg->x11->RegisterCallback(dlg->x11, dlg->win.self, dlg->wDad,
621 DlgCB, dlg);
622 dlg->x11->SetInputMask(dlg->x11, dlg->win.self,
623 ExposureMask | ButtonPressMask | KeyPressMask);
625 if (!CheckWindow(dlg->win.self))
627 std::exit(1);
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 */
645 0, /* edlgPM */
646 ExposureMask, /* edlgST */
647 ExposureMask | UserMask | EnterLeaveMask /* edlgET */
650 if (!dlg->win.self)
652 DoCreateDlg(dlg);
654 srenew(dlg->dlgitem, dlg->nitem+1);
655 if (!item)
657 gmx_fatal(FARGS, "dlgitem not allocated");
659 item->win.self =
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,
666 DlgCB, dlg);
667 dlg->x11->SetInputMask(dlg->x11, item->win.self, InputMask[item->type]);
669 switch (item->type)
671 case edlgPM:
672 XSetWindowBackgroundPixmap(dlg->x11->disp, item->win.self, item->u.pixmap.pm);
673 break;
674 default:
675 break;
677 dlg->dlgitem[dlg->nitem] = item;
679 dlg->nitem++;
682 void AddDlgItems(t_dlg *dlg, int nitem, t_dlgitem *item[])
684 int i;
686 for (i = 0; (i < nitem); i++)
688 #ifdef DEBUG
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);
692 #endif
693 AddDlgItem(dlg, item[i]);
697 void FreeDlgItem(t_dlg *dlg, t_id id)
699 t_dlgitem *dlgitem;
700 int i;
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)
712 case edlgBN:
713 case edlgRB:
714 break;
715 case edlgGB:
716 sfree(dlgitem->u.groupbox.item);
717 break;
718 case edlgCB:
719 break;
720 case edlgPM:
721 XFreePixmap(dlg->x11->disp, dlgitem->u.pixmap.pm);
722 break;
723 case edlgST:
724 for (i = 0; (i < dlgitem->u.statictext.nlines); i++)
726 sfree(dlgitem->u.statictext.lines[i]);
728 sfree(dlgitem->u.statictext.lines);
729 break;
730 case edlgET:
731 sfree(dlgitem->u.edittext.buf);
732 break;
733 default:
734 break;
739 void FreeDlg(t_dlg *dlg)
741 int i;
743 if (dlg->dlgitem)
745 HideDlg(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);
750 if (dlg->dlgitem[i])
752 sfree(dlg->dlgitem[i]);
755 sfree(dlg->dlgitem);
756 if (dlg->win.self)
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)
773 t_dlg *dlg;
774 int x = 0, y = 0;
776 snew(dlg, 1);
777 dlg->x11 = x11;
778 dlg->cb = cb;
779 dlg->data = data;
780 if (title)
782 dlg->title = gmx_strdup(title);
784 else
786 dlg->title = nullptr;
788 if (w == 0)
790 w = 1;
792 if (h == 0)
794 h = 1;
796 if (!Parent)
798 Parent = x11->root;
799 dlg->xmax = DisplayWidth(x11->disp, x11->screen);
800 dlg->ymax = DisplayHeight(x11->disp, x11->screen);
802 else
804 Window root;
805 unsigned int dum;
807 XGetGeometry(x11->disp, Parent, &root, &x, &y,
808 &(dlg->xmax), &(dlg->ymax), &dum, &dum);
809 #ifdef DEBUG
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);
813 #endif
815 if (x0)
817 x = x0;
819 if (y0)
821 y = y0;
823 InitWin(&(dlg->win), x, y, w, h, bw, nullptr);
824 SetDlgSize(dlg, w, h, x0 || y0);
826 dlg->wDad = Parent;
827 dlg->fg = x11->fg;
828 dlg->bg = x11->bg;
829 dlg->nitem = 0;
830 dlg->dlgitem = nullptr;
832 DoCreateDlg(dlg);
833 return dlg;
836 void SetDlgSize(t_dlg *dlg, int w, int h, bool bAutoPosition)
838 if (bAutoPosition)
840 int x, y;
842 x = (dlg->xmax-w)/2;
843 y = (dlg->ymax-h)/2;
844 dlg->win.x = x;
845 dlg->win.y = y;
847 dlg->win.width = w;
848 dlg->win.height = h;
850 #ifdef DEBUG
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);
854 #endif
855 if (dlg->win.self)
857 XMoveWindow(dlg->x11->disp, dlg->win.self, dlg->win.x, dlg->win.y);
858 XResizeWindow(dlg->x11->disp, dlg->win.self, w, h);