5a043422add0fd19f0c2ffa15aab7fe8da372f95
[alexxy/gromacs.git] / src / programs / view / xdlgitem.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2013, The GROMACS development team.
6  * Copyright (c) 2013,2014, 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.
10  *
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.
15  *
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.
20  *
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.
25  *
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.
33  *
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.
36  */
37 #include "gmxpre.h"
38
39 #include "config.h"
40
41 #include <ctype.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <algorithm>
47
48 #include "gromacs/legacyheaders/macros.h"
49 #include "Xstuff.h"
50 #include "xdlgitem.h"
51
52 #include "gromacs/utility/cstringutil.h"
53 #include "gromacs/utility/fatalerror.h"
54 #include "gromacs/utility/smalloc.h"
55
56 #define BUFSIZE 16
57
58 static t_dlgitem *newitem(void)
59 {
60     t_dlgitem *item;
61
62     snew(item, 1);
63
64     return item;
65 }
66
67 /*****************************
68  *
69  * Window Procedures and helpful functions
70  *
71  ****************************/
72 static void ShowCaret(t_x11 *x11, t_dlgitem *dlgitem)
73 {
74     t_edittext *et;
75
76     if (dlgitem->type == edlgET)
77     {
78         int x, y1, y2;
79
80         et = &(dlgitem->u.edittext);
81         x  = XTextWidth(x11->font, dlgitem->win.text, strlen(dlgitem->win.text))+XCARET+
82             XTextWidth(x11->font, (char*) &(et->buf[et->strbegin]), et->pos);
83         y1 = (dlgitem->win.height-XTextHeight(x11->font))/2;
84         y2 = (dlgitem->win.height-y1);
85         y1--, y2++;
86         XDrawLine(x11->disp, dlgitem->win.self, x11->gc, x-XCARET, y1, x+XCARET, y1);
87         XDrawLine(x11->disp, dlgitem->win.self, x11->gc, x, y1, x, y2);
88         XDrawLine(x11->disp, dlgitem->win.self, x11->gc, x-XCARET, y2, x+XCARET, y2);
89     }
90 }
91
92 static void HideCaret(t_x11 *x11, t_dlgitem *dlgitem)
93 {
94     XSetForeground(x11->disp, x11->gc, x11->bg);
95     ShowCaret(x11, dlgitem);
96     XSetForeground(x11->disp, x11->gc, x11->fg);
97 }
98
99 static int DefWndProc(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
100 {
101     XComposeStatus status;
102     KeySym         keysym;
103     char           c[BUFSIZE+1];
104
105 #ifdef DEBUG
106     printf("DefWndProc\n");
107 #endif
108     switch (event->type)
109     {
110         case Expose:
111         case ButtonPress:
112         case KeyPress:
113             if (HelpPressed(event))
114             {
115                 return HELPPRESSED;
116             }
117             else
118             {
119                 XLookupString(&(event->xkey), c, BUFSIZE, &keysym, &status);
120                 if ((keysym == XK_Return) || (keysym == XK_KP_Enter))
121                 {
122                     return ENTERPRESSED;
123                 }
124             }
125             break;
126         case EnterNotify:
127             dlgitem->win.bFocus = true;
128             ShowCaret(x11, dlgitem);
129             /*    LightBorder(x11->disp,dlgitem->win.self,x11->fg); */
130             break;
131         case LeaveNotify:
132             dlgitem->win.bFocus = false;
133             HideCaret(x11, dlgitem);
134             /*    LightBorder(x11->disp,dlgitem->win.self,x11->bg); */
135             break;
136         default:
137             XBell(x11->disp, 50);
138     }
139     return ITEMOK;
140 }
141
142 static int WndProcBN(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
143 {
144     t_windata *win;
145     int        x, w, th;
146
147     if (dlgitem->type != edlgBN)
148     {
149         gmx_incons("button processing");
150     }
151     win = &(dlgitem->win);
152     w   = XTextWidth(x11->font, win->text, strlen(win->text));
153     x   = (win->width-w)/2;
154     th  = XTextHeight(x11->font)+OFFS_Y;
155     switch (event->type)
156     {
157         case Expose:
158             RectWin(x11->disp, x11->gc, win, x11->fg);
159             TextInRect(x11, win->self, win->text, 0, 0, win->width, th, eXCenter, eYCenter);
160             break;
161         case ButtonPress:
162             return BNPRESSED;
163         case EnterNotify:
164             XDrawLine(x11->disp, win->self, x11->gc, x-1, th, x+w, th);
165             break;
166         case LeaveNotify:
167             XSetForeground(x11->disp, x11->gc, x11->bg);
168             XDrawLine(x11->disp, win->self, x11->gc, x-1, th, x+w, th);
169             XSetForeground(x11->disp, x11->gc, x11->fg);
170             break;
171         default:
172             return DefWndProc(x11, dlgitem, event);
173     }
174     return ITEMOK;
175 }
176
177 static int WndProcRB(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
178 {
179     t_radiobutton *rb;
180     t_windata     *win;
181     int            x, y, rad;
182
183     if (dlgitem->type != edlgRB)
184     {
185         gmx_incons("radiobutton processing");
186     }
187     rb  = &(dlgitem->u.radiobutton);
188     win = &(dlgitem->win);
189
190     rad = win->height/3;
191     x   = rad;
192     y   = win->height/2;
193     switch (event->type)
194     {
195         case Expose:
196             XClearArea(x11->disp, win->self, x-rad, y-rad, x+rad, y+rad, False);
197             if (rb->bSelect)
198             {
199                 /* Filled */
200                 XFillCircle(x11->disp, win->self, x11->gc, x, y, rad);
201             }
202             XDrawCircle(x11->disp, win->self, x11->gc, x, y, rad);
203             x += rad+OFFS_X;
204             TextInRect(x11, win->self, win->text, x, 0, win->width-x, win->height,
205                        eXLeft, eYCenter);
206             break;
207         case ButtonPress:
208             if (!rb->bSelect)
209             {
210                 return RBPRESSED;
211             }
212             XBell(x11->disp, 50);
213             break;
214         case EnterNotify:
215         case LeaveNotify:
216             break;
217         default:
218             return DefWndProc(x11, dlgitem, event);
219     }
220     return ITEMOK;
221 }
222
223 static int WndProcGB(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
224 {
225     t_windata *win;
226     int        x, y;
227
228     if (dlgitem->type != edlgGB)
229     {
230         gmx_incons("gb processing");
231     }
232     win = &(dlgitem->win);
233
234     x = XTextWidth(x11->font, win->text, strlen(win->text));
235     y = XTextHeight(x11->font);
236     switch (event->type)
237     {
238         case Expose:
239             XSetForeground(x11->disp, x11->gc, x11->fg);
240             XDrawRoundRect(x11->disp, win->self, x11->gc, 0, y/2,
241                            win->width-1, win->height-y/2-1);
242             XClearArea(x11->disp, win->self, OFFS_X, 0, x+OFFS_X, y, False);
243             TextInRect(x11, win->self, win->text, 2*OFFS_X, 0, x, y, eXCenter, eYCenter);
244             break;
245         case EnterNotify:
246         case LeaveNotify:
247             break;
248         default:
249             return DefWndProc(x11, dlgitem, event);
250     }
251     return ITEMOK;
252 }
253
254 static int WndProcCB(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
255 {
256     t_checkbox *cb;
257     t_windata  *win;
258     int         x, y, w, h;
259
260     if (dlgitem->type != edlgCB)
261     {
262         gmx_incons("check box processing");
263     }
264     cb  = &(dlgitem->u.checkbox);
265     win = &(dlgitem->win);
266
267     x = 0;
268     y = win->height/7;
269     w = 5*y;
270     h = 5*y;
271     switch (event->type)
272     {
273         case Expose:
274             XSetForeground(x11->disp, x11->gc, x11->fg);
275             XClearArea(x11->disp, win->self, x, y, w, h, False);
276             XDrawRectangle(x11->disp, win->self, x11->gc, x, y, w, h);
277             if (cb->bChecked)
278             {
279                 XDrawLine(x11->disp, win->self, x11->gc, x, y, x+w, y+h);
280                 XDrawLine(x11->disp, win->self, x11->gc, x+w, y, x, y+h);
281             }
282             x = w+OFFS_X;
283             TextInRect(x11, win->self, win->text, x, 0, win->width-x, win->height,
284                        eXLeft, eYCenter);
285             break;
286         case ButtonPress:
287             cb->bChecked = !cb->bChecked;
288             return CBPRESSED;
289         case EnterNotify:
290         case LeaveNotify:
291             break;
292         default:
293             return DefWndProc(x11, dlgitem, event);
294     }
295     return ITEMOK;
296 }
297
298 static int WndProcST(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
299 {
300     t_statictext *st;
301     t_windata    *win;
302     int           i, dy;
303
304     if (dlgitem->type != edlgST)
305     {
306         gmx_incons("st processing");
307     }
308     st  = &(dlgitem->u.statictext);
309     win = &(dlgitem->win);
310
311     switch (event->type)
312     {
313         case Expose:
314             dy = XTextHeight(x11->font)+OFFS_Y;
315             for (i = 0; (i < st->nlines); i++)
316             {
317                 TextInRect(x11, win->self, st->lines[i],
318                            0, OFFS_Y+i*dy, win->width, dy, eXLeft, eYCenter);
319             }
320             break;
321         default:
322             return DefWndProc(x11, dlgitem, event);
323     }
324     return ITEMOK;
325 }
326
327 static bool insert(char *s, char c, int *pos)
328 {
329     int i, sl;
330
331     if (isprint(c))
332     {
333         sl = strlen(s);
334         /* +1 for zero termination */
335         for (i = sl+1; (i > *pos); i--)
336         {
337             s[i+1] = s[i];
338         }
339         s[*pos] = c;
340         (*pos)++;
341         return true;
342     }
343     return false;
344 }
345
346 static bool my_backspace(char *s, int *pos)
347 {
348     int i, sl;
349
350     sl = strlen(s);
351     if ((sl > 0) && ((*pos) > 0))
352     {
353         for (i = *pos-1; (i < sl); i++)
354         {
355             s[i] = s[i+1];
356         }
357         (*pos) = std::max(0, (*pos)-1);
358         return true;
359     }
360     return false;
361 }
362
363 static bool my_delete(char *s, int *pos)
364 {
365     int i, sl;
366
367     sl = strlen(s);
368     if ((sl > 0) && ((*pos) < sl))
369     {
370         for (i = *pos; (i < sl); i++)
371         {
372             s[i] = s[i+1];
373         }
374         return true;
375     }
376     return false;
377 }
378
379 static int WndProcET(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event)
380 {
381     t_edittext  *et;
382     t_windata   *win;
383     KeySym       keysym;
384     char         c[BUFSIZE+1], *bp;
385     char         scrbuf[STRLEN];
386     int          i;
387     int          xp, xtitle, ewidth;
388
389     if (dlgitem->type != edlgET)
390     {
391         gmx_incons("st processing");
392     }
393     et  = &(dlgitem->u.edittext);
394     win = &(dlgitem->win);
395
396     /* Copy string part that is visible into screen buffer */
397     for (i = 0; (i < et->buflen); i++)
398     {
399         scrbuf[i] = et->buf[i+et->strbegin];
400     }
401     scrbuf[i] = '\0';
402
403     switch (event->type)
404     {
405         case Expose:
406             XSetForeground(x11->disp, x11->gc, x11->fg);
407             xtitle = XTextWidth(x11->font, win->text, strlen(win->text));
408             ewidth = win->width-xtitle;
409             TextInRect(x11, win->self, win->text,
410                        0, 0, xtitle-1, win->height, eXLeft, eYCenter);
411             XClearArea(x11->disp, win->self, xtitle, 0, ewidth+XCARET, win->height, False);
412             TextInRect(x11, win->self, scrbuf,
413                        xtitle+XCARET, 0, ewidth, win->height, eXLeft, eYCenter);
414 #ifdef DEBUG
415             printf("Expose\n");
416 #endif
417             if (win->bFocus)
418             {
419                 ShowCaret(x11, dlgitem);
420             }
421             break;
422         case ButtonPress:
423             /* Calculate new position for caret */
424             et->pos = strlen(et->buf);
425             bp      = gmx_strdup(et->buf);
426             xp      = event->xbutton.x-XTextWidth(x11->font, win->text, strlen(win->text))-
427                 XCARET;
428             while ((et->pos > 0) && (XTextWidth(x11->font, bp, strlen(bp)) > xp))
429             {
430                 et->pos--;
431                 bp[et->pos] = '\0';
432             }
433             sfree(bp);
434             et->bChanged = true;
435             return ETCHANGED;
436         case KeyPress:
437             /* Check for HelpKey */
438             if (HelpPressed(event))
439             {
440                 return DefWndProc(x11, dlgitem, event);
441             }
442             XLookupString(&(event->xkey), c, BUFSIZE, &keysym, NULL);
443 #ifdef DEBUG
444             printf("Keysym: %x\n", keysym);
445 #endif
446             switch (keysym)
447             {
448                 case XK_Delete:
449                     if (my_delete(et->buf, &(et->pos)))
450                     {
451                         et->bChanged = true;
452                         return ETCHANGED;
453                     }
454                     else
455                     {
456                         XBell(x11->disp, 50);
457                     }
458                     break;
459                 case XK_BackSpace:
460                     if (my_backspace(et->buf, &(et->pos)))
461                     {
462                         et->bChanged = true;
463                         return ETCHANGED;
464                     }
465                     else
466                     {
467                         XBell(x11->disp, 50);
468                     }
469                     break;
470                 case XK_KP_Enter:
471                 case XK_Return:
472                     return ENTERPRESSED;
473                 case XK_Home:
474                     et->pos      = 0;
475                     et->strbegin = 0;
476                     et->bChanged = true;
477                     return ETCHANGED;
478                 case XK_End:
479                     if (strlen(et->buf) <= (unsigned int)et->buflen)
480                     {
481                         et->pos = strlen(et->buf);
482                     }
483                     else
484                     {
485                         et->pos      = et->buflen;
486                         et->strbegin = strlen(et->buf)-et->buflen;
487                     }
488                     et->bChanged = true;
489                     return ETCHANGED;
490                 case XK_Left:
491                     et->pos      = std::max(0, et->pos-1);
492                     et->strbegin = std::min(et->strbegin, et->pos);
493                     et->bChanged = true;
494                     return ETCHANGED;
495                 case XK_Right:
496                     if ((et->pos < et->buflen) &&
497                         (et->strbegin+et->buflen > (int)strlen(et->buf)))
498                     {
499                         et->pos++;
500                     }
501                     else if ((et->buflen   < (int)strlen(et->buf)) &&
502                              (et->strbegin < (int)strlen(et->buf)-et->buflen))
503                     {
504                         et->strbegin++;
505                     }
506                     else
507                     {
508                         break;
509                     }
510                     et->bChanged = true;
511                     return ETCHANGED;
512                 default:
513                     if (keysym < 256)
514                     {
515                         if (insert(et->buf, c[0], &(et->pos)))
516                         {
517                             et->bChanged = true;
518                             return ETCHANGED;
519                         }
520                     }
521                     XBell(x11->disp, 50);
522                     break;
523             }
524             break;
525         case LeaveNotify:
526             win->bFocus = false;
527             HideCaret(x11, dlgitem);
528             if (et->bChanged)
529             {
530                 et->bChanged = false;
531             }
532             break;
533         default:
534             return DefWndProc(x11, dlgitem, event);
535     }
536     return ITEMOK;
537 }
538
539 /*****************************
540  *
541  * Routines to create dialog items, all items have an id
542  * which you can use to extract info. It is possible to have
543  * multiple items with the same id but it may then not be possible
544  * to extract information.
545  * All routines take the position relative to the parent dlg
546  * and the size and border width.
547  * If the width and height are set to zero initially, they will
548  * be calculated and set by the routine. With the dlgitem manipulation
549  * routines listed below, the application can then move the items around
550  * on the dlg box, and if wished resize them.
551  *
552  ****************************/
553 t_dlgitem *CreateButton(t_x11 *x11,
554                         const char *szLab, bool bDef, t_id id, t_id groupid,
555                         int x0, int y0, int w, int h, int bw)
556 {
557     t_dlgitem *dlgitem;
558     char      *lab;
559
560     dlgitem = newitem();
561     if (h == 0)
562     {
563         h = XTextHeight(x11->font)+2*OFFS_Y;
564     }
565     if (w == 0)
566     {
567         w = XTextWidth(x11->font, szLab, strlen(szLab))+2*OFFS_X;
568     }
569     if (bDef)
570     {
571         snew(lab, strlen(szLab)+7); /* 6 for >> << and 1 for \0 */
572         sprintf(lab, ">> %s <<", szLab);
573     }
574     else
575     {
576         lab = gmx_strdup(szLab);
577     }
578     InitWin(&(dlgitem->win), x0, y0, w, h, bw, szLab);
579     sfree(lab);
580     dlgitem->ID                = id;
581     dlgitem->GroupID           = groupid;
582     dlgitem->type              = edlgBN;
583     dlgitem->u.button.bDefault = bDef;
584     dlgitem->WndProc           = WndProcBN;
585
586     return dlgitem;
587 }
588
589 t_dlgitem *CreateRadioButton(t_x11 *x11,
590                              const char *szLab, bool bSet, t_id id,
591                              t_id groupid,
592                              int x0, int y0, int w, int h, int bw)
593 {
594     t_dlgitem *dlgitem;
595
596     dlgitem = newitem();
597     if (h == 0)
598     {
599         h = XTextHeight(x11->font)+OFFS_Y;
600     }
601     if (w == 0)
602     {
603         w = XTextWidth(x11->font, szLab, strlen(szLab))+OFFS_X+h;
604     }
605     InitWin(&(dlgitem->win), x0, y0, w, h, bw, szLab);
606     dlgitem->ID                    = id;
607     dlgitem->GroupID               = groupid;
608     dlgitem->type                  = edlgRB;
609     dlgitem->u.radiobutton.bSelect = bSet;
610     dlgitem->WndProc               = WndProcRB;
611
612     return dlgitem;
613 }
614
615 t_dlgitem *CreateGroupBox(t_x11 *x11,
616                           const char *szLab, t_id id,
617                           int nitems, t_id items[],
618                           int x0, int y0, int w, int h, int bw)
619 {
620     t_dlgitem *dlgitem;
621
622     dlgitem = newitem();
623     if (h == 0)
624     {
625         h = XTextHeight(x11->font)+OFFS_Y;
626     }
627     if (w == 0)
628     {
629         w = XTextWidth(x11->font, szLab, strlen(szLab))+2*OFFS_X;
630     }
631     InitWin(&(dlgitem->win), x0, y0, w, h, bw, szLab);
632     dlgitem->GroupID           = id;
633     dlgitem->ID                = id;
634     dlgitem->type              = edlgGB;
635     dlgitem->u.groupbox.nitems = nitems;
636     snew(dlgitem->u.groupbox.item, nitems);
637     memcpy((char *)dlgitem->u.groupbox.item, (char *)items,
638            nitems*sizeof(items[0]));
639     dlgitem->WndProc = WndProcGB;
640
641     return dlgitem;
642 }
643
644 t_dlgitem *CreateCheckBox(t_x11 *x11,
645                           const char *szLab, bool bCheckedInitial, t_id id,
646                           t_id groupid,
647                           int x0, int y0, int w, int h, int bw)
648 {
649     t_dlgitem *dlgitem;
650
651     dlgitem = newitem();
652     if (h == 0)
653     {
654         h = XTextHeight(x11->font)+OFFS_Y;
655     }
656     if (w == 0)
657     {
658         w = XTextWidth(x11->font, szLab, strlen(szLab))+OFFS_X+h;
659     }
660     InitWin(&(dlgitem->win), x0, y0, w, h, bw, szLab);
661     dlgitem->ID                  = id;
662     dlgitem->GroupID             = groupid;
663     dlgitem->type                = edlgCB;
664     dlgitem->u.checkbox.bChecked = bCheckedInitial;
665     dlgitem->WndProc             = WndProcCB;
666
667     return dlgitem;
668 }
669
670 t_dlgitem *CreatePixmap(Pixmap pm, t_id id,
671                         t_id /*groupid*/, int x0, int y0, int w, int h, int bw)
672 {
673     t_dlgitem *dlgitem;
674
675     dlgitem = newitem();
676     InitWin(&(dlgitem->win), x0, y0, w, h, bw, NULL);
677     dlgitem->ID          = id;
678     dlgitem->type        = edlgPM;
679     dlgitem->u.pixmap.pm = pm;
680     dlgitem->WndProc     = DefWndProc;
681
682     return dlgitem;
683 }
684
685 t_dlgitem *CreateStaticText(t_x11 *x11,
686                             int nlines, const char * const *lines, t_id id,
687                             t_id groupid,
688                             int x0, int y0, int w, int h, int bw)
689 {
690     t_dlgitem *dlgitem;
691     int        i;
692
693     dlgitem = newitem();
694     if (h == 0)
695     {
696         h = (XTextHeight(x11->font)+OFFS_Y)*nlines+OFFS_Y;
697     }
698     if (w == 0)
699     {
700         for (i = 0; (i < nlines); i++)
701         {
702             w = std::max(w, XTextWidth(x11->font, lines[i], strlen(lines[i])));
703         }
704         w += 2*OFFS_X;
705     }
706     InitWin(&(dlgitem->win), x0, y0, w, h, bw, NULL);
707     dlgitem->ID                  = id;
708     dlgitem->GroupID             = groupid;
709     dlgitem->type                = edlgST;
710     dlgitem->u.statictext.nlines = nlines;
711     snew(dlgitem->u.statictext.lines, nlines);
712     for (i = 0; (i < nlines); i++)
713     {
714         dlgitem->u.statictext.lines[i] = gmx_strdup(lines[i]);
715     }
716     dlgitem->WndProc = WndProcST;
717
718     return dlgitem;
719 }
720
721 t_dlgitem *CreateEditText(t_x11 *x11,
722                           const char *title,
723                           int screenbuf, char *buf, t_id id, t_id groupid,
724                           int x0, int y0, int w, int h, int bw)
725 {
726     t_dlgitem  *dlgitem;
727     t_edittext *et;
728
729     dlgitem = newitem();
730     if (h == 0)
731     {
732         h = XTextHeight(x11->font)+OFFS_Y;
733     }
734     if (w == 0)
735     {
736         char *test;
737
738         snew(test, screenbuf);
739         memset(test, 'w', screenbuf);
740         w = XTextWidth(x11->font, test, screenbuf)+
741             XTextWidth(x11->font, title, strlen(title))+
742             2*XCARET+2*OFFS_X;
743         sfree(test);
744     }
745     InitWin(&(dlgitem->win), x0, y0, w, h, bw, title);
746     dlgitem->ID      = id;
747     dlgitem->GroupID = groupid;
748     dlgitem->type    = edlgET;
749     et               = &(dlgitem->u.edittext);
750     snew(et->buf, STRLEN);
751     strcpy(et->buf, buf);
752     et->buflen       = screenbuf;
753     et->strbegin     = 0;
754     et->bChanged     = false;
755     dlgitem->WndProc = WndProcET;
756
757     return dlgitem;
758 }
759
760 #define SC(src) (strlen(src) ? gmx_strdup(src) : NULL)
761
762 void SetDlgitemOpts(t_dlgitem *dlgitem, bool bUseMon,
763                     char *set, char *get, char *help)
764 {
765     dlgitem->bUseMon = bUseMon;
766     dlgitem->set     = SC(set);
767     dlgitem->get     = SC(get);
768     dlgitem->help    = SC(help);
769 #ifdef DEBUG
770     printf("Help is: '%s'\n", dlgitem->help);
771 #endif
772 }