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