1 /*
2  *  WINDOW.C
3  *
4  *  Written by John Dennis and released to the public domain on 10-Jul-94.
5  *
6  *  This module contains routines that maintain text windows on the
7  *  screen.  Output routines are integrated in relation to the window
8  *  coordinates on the screen.  All coordinates have a 0 based origin!
9  *  Please note this!
10  *
11  *  This is the second level of abstraction from the physical device; it
12  *  should not be necessary to modify this module when porting to other
13  *  operating systems/devices.
14  *
15  *  History:
16  *
17  *  10-Nov-91 JD Started.
18  *  25-Jul-92 JD Whole package (of which this is a module) was finished
19  *               to a useable degree.
20  *  13-Aug-92 JD Functions added during the Msged port to this system.
21  *               Should increase the packages' useability.
22  */
23 
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <time.h>
28 #include "specch.h"
29 #include "memextra.h"
30 #include "keys.h"
31 #include "winsys.h"
32 #include "mcompile.h"
33 
34 #define XMOD(w) ((w->flags & INSBDR) ? 3 : ((w->flags & NBDR) ? 0 : 1))
35 #define YMOD(w) ((w->flags & INSBDR) ? 2 : ((w->flags & NBDR) ? 0 : 1))
36 
37 /* double and single border chars */
38 /*
39 unsigned char Dbdr[6] = {SC1, SC2, SC3, SC4, SC5, SC6};
40 unsigned char Sbdr[6] = {SC7, SC8, SC9, SC10, SC11, SC12};
41 */
42 
43 #define Dbdr(x) SC(((x)+1))
44 #define Sbdr(x) SC(((x)+7))
45 #define Bdr(y,x) (((y) != SBDR) ? Dbdr((x)) : Sbdr((x)))
46 
47 
48 int wnd_bs_127 = 0;           /* Is ASCII 127 backspace on ANSI console ? */
49 int wnd_suppress_shadows = 0; /* do not suppress window shadows */
50 #ifdef UNIX
51 int wnd_force_monochrome = 1;
52 #else
53 int wnd_force_monochrome = 0; /* do not enforce monochrome output */
54 #endif
55 
56 unsigned long wndid = 20;     /* unique window ID */
57 WND *CW = NULL;               /* current window */
58 
59 static void WDrwBox(int x1, int y1, int x2, int y2, int Bdrt, int Battr, int ins);
60 
61 static char line[255];
62 
CheckMousePos(int x1,int y1,int x2,int y2)63 int CheckMousePos(int x1, int y1, int x2, int y2)
64 {
65     int x, y;
66     GetMouInfo(&x, &y);
67     if (x >= x1 && x <= x2)
68     {
69         if (y >= y1 && y <= y2)
70         {
71             return 1;
72         }
73     }
74     return 0;
75 }
76 
77 /*
78  *  WndOpen; Creates and opens a window returning the handle to
79  *  the user, using 0 based coordinates on the screen.
80  */
81 
WndOpen(int x1,int y1,int x2,int y2,int Bdr,int BAttr,int Attr)82 WND *WndOpen(int x1, int y1, int x2, int y2, int Bdr, int BAttr, int Attr)
83 {
84     WND *w;
85     unsigned long ch;
86     int i, k = 0;
87     static int first_win = 1;
88 
89     w = xmalloc(sizeof *w);
90 
91     if (w == NULL)
92     {
93         return NULL;
94     }
95 
96     if (wnd_suppress_shadows)
97     {
98         Bdr = Bdr & (~SHADOW);
99     }
100 
101     /* sanity checks*/
102     if (x1 < 0)  x1 = 0;
103     if (y1 < 0)  y1 = 0;
104     if (x2 < x1) x2 = x1;
105     if (y2 < y1) y2 = y1;
106 
107     w->wid = ++wndid;
108     w->x1 = (unsigned char)x1;
109     w->x2 = (unsigned char)x2;
110     w->y1 = (unsigned char)y1;
111     w->y2 = (unsigned char)y2;
112     w->wattr = (unsigned char)Attr;
113     w->battr = (unsigned char)BAttr;
114     w->flags = (unsigned char)Bdr;
115     w->title = NULL;
116 
117     if (Bdr & SHADOW)
118     {
119         x2 += 2;
120         y2++;
121     }
122 
123     MouseOFF();
124 
125     /* get a copy of the background */
126 
127     if ((!(Bdr & NOSAVE)) || (Bdr & SHADOW))
128     {
129         w->buffer = xmalloc(sizeof(unsigned long *) * ((y2 - y1) + 2));
130 
131         if (!w->buffer)
132         {
133             return NULL;
134         }
135 
136         for (i = y1; i <= y2; i++)
137         {
138             w->buffer[k] = xmalloc(sizeof(unsigned long) * ((x2 - x1) + 2));
139             if (!w->buffer[k])
140             {
141                 return NULL;
142             }
143             TTReadStr(w->buffer[k], x2 - x1 + 1, i, x1);
144             k++;
145         }
146     }
147     else
148     {
149         w->buffer = NULL;
150     }
151 
152     TTBeginOutput();
153 
154     /* put out shadow */
155 
156     if (Bdr & SHADOW)
157     {
158         k = 1;
159         for (i = y1 + 1; i <= y2; i++)
160         {
161             ch = (unsigned long)w->buffer[k][x2 - x1];
162             ch &= 0xFF00FFFFUL;
163             ch |= ((unsigned long)(DGREY | _BLACK) << 16);
164             TTWriteStr(&ch, 1, i, x2);
165             ch = (unsigned long)w->buffer[k][x2 - x1 - 1];
166             ch &= 0xFF00FFFFUL;
167             ch |= ((unsigned long)(DGREY | _BLACK) << 16);
168             TTWriteStr(&ch, 1, i, x2 - 1);
169             k++;
170         }
171         k = y2 - y1;
172         for (i = 2; i <= (x2 - x1); i++)
173         {
174             ch = (unsigned long)w->buffer[k][i];
175             ch &= 0xFF00FFFFUL;
176             ch |= ((unsigned long)(DGREY | _BLACK) << 16);
177             TTWriteStr(&ch, 1, y2, i + x1);
178         }
179     }
180     TTScolor(Attr);
181     if (!first_win)
182     {
183         TTClear(w->x1, w->y1, w->x2, w->y2);
184     }
185     else
186     {
187         first_win = 0;
188     }
189 
190     if (!(Bdr & NBDR))
191     {
192         if (Bdr & SBDR)
193         {
194             WDrwBox(w->x1, w->y1, w->x2, w->y2, SBDR, BAttr, Bdr & INSBDR ? 1 : 0);
195         }
196         else
197         {
198             WDrwBox(w->x1, w->y1, w->x2, w->y2, DBDR, BAttr, Bdr & INSBDR ? 1 : 0);
199         }
200     }
201 
202     MouseON();
203 
204     TTEndOutput();
205 
206     CW = w;
207 
208     return CW;
209 }
210 
211 /*
212  *  WndPopUp; Opens up a window of the passed size in the middle of the
213  *  screen.
214  */
215 
WndPopUp(int wid,int dep,int Bdr,int BAttr,int NAttr)216 WND *WndPopUp(int wid, int dep, int Bdr, int BAttr, int NAttr)
217 {
218     int x1, x2, y1, y2;
219     x1 = max((term.NCol / 2) - (wid / 2) - 1, 0);
220     y1 = max((term.NRow / 2) - (dep / 2) - 1, 0);
221     x2 = min(x1 + wid, term.NCol - 1);
222     y2 = min(y1 + dep, term.NRow - 1);
223     return WndOpen(x1, y1, x2, y2, Bdr, BAttr, NAttr);
224 }
225 
226 /*
227  *  WndClose; Closes the passed window and restores the screen
228  *  behind it.
229  *
230  *  Caveats: Since no track is kept of the windows on the screen, it
231  *  is the caller's responsibility to ensure that windows are closed
232  *  in the right order.
233  */
234 
WndClose(WND * w)235 void WndClose(WND * w)
236 {
237     WND *wnd;
238     int i, k = 0;
239     int x2, y2;
240 
241     /* restore screen buffer */
242 
243     if (w == NULL)
244     {
245         wnd = CW;
246     }
247     else
248     {
249         wnd = w;
250     }
251 
252     if (wnd == NULL)
253     {
254         return;
255     }
256 
257     x2 = wnd->x2;
258     y2 = wnd->y2;
259 
260     if (wnd->flags & SHADOW)
261     {
262         x2 += 2;
263         y2++;
264     }
265 
266     TTBeginOutput();
267     MouseOFF();
268 
269     if (!(wnd->flags & NOSAVE))
270     {
271         for (i = wnd->y1; i <= y2; i++)
272         {
273             TTWriteStr(wnd->buffer[k], x2 - wnd->x1 + 1, i, wnd->x1);
274             xfree(wnd->buffer[k++]);
275         }
276         xfree(wnd->buffer);
277     }
278     xfree(wnd);
279     MouseON();
280     TTEndOutput();
281 }
282 
283 /*
284  *  WndDrwBox; Draws a box at the specified position. Internal function.
285  */
286 
WDrwBox(int x1,int y1,int x2,int y2,int Bdrt,int Battr,int ins)287 static void WDrwBox(int x1, int y1, int x2, int y2, int Bdrt, int Battr, int ins)
288 {
289     unsigned int i, width;
290     unsigned long cell, *pcell, *p;
291     int xmod = ins ? 2 : 0;
292     int ymod = ins ? 1 : 0;
293 
294     TTBeginOutput();
295     MouseOFF();
296 
297     /* write corner chars */
298 
299     cell = MAKECELL(Bdr(Bdrt,2), Battr | F_ALTERNATE);
300     TTWriteStr(&cell, 1, y1 + ymod, x1 + xmod);
301 
302     cell = MAKECELL(Bdr(Bdrt,3), Battr | F_ALTERNATE);
303     TTWriteStr(&cell, 1, y1 + ymod, x2 - xmod);
304 
305     cell = MAKECELL(Bdr(Bdrt,4), Battr | F_ALTERNATE);
306     TTWriteStr(&cell, 1, y2 - ymod, x1 + xmod);
307 
308     cell = MAKECELL(Bdr(Bdrt,5), Battr | F_ALTERNATE);
309     TTWriteStr(&cell, 1, y2 - ymod, x2 - xmod);
310 
311 
312     /* write top & bottom horiziontal border chars */
313 
314     width = (x2 - xmod) - (x1 + 1 + xmod);
315     pcell = xmalloc(width * sizeof *pcell);
316     p = pcell;
317     for (i = 0; i < width; i++)
318     {
319         *p = MAKECELL(Bdr(Bdrt,1), Battr | F_ALTERNATE);
320         p++;
321     }
322     TTWriteStr(pcell, width, y1 + ymod, x1 + 1 + xmod);
323     TTWriteStr(pcell, width, y2 - ymod, x1 + 1 + xmod);
324     xfree(pcell);
325 
326     /* write left & right vertical border chars */
327 
328     cell = MAKECELL(Bdr(Bdrt,0), Battr | F_ALTERNATE);
329     for (i = y1 + 1 + ymod; i < y2 - ymod; i++)
330     {
331         TTWriteStr(&cell, 1, i, x1 + xmod);
332         TTWriteStr(&cell, 1, i, x2 - xmod);
333     }
334 
335     TTEndOutput();
336     MouseON();
337 }
338 
339 /*
340  *  WndBox; Draws a box in the window.
341  */
342 
WndBox(int x1,int y1,int x2,int y2,int Attr,int type)343 void WndBox(int x1, int y1, int x2, int y2, int Attr, int type)
344 {
345     int xmod, ymod;
346     int Bdrt = (type & DBDR) ? DBDR : SBDR;
347 
348     if (CW == NULL)
349     {
350         return;
351     }
352 
353     ymod = YMOD(CW);
354     xmod = XMOD(CW);
355 
356     if (y1 < 0 || x1 < 0 || CW->x1 + x2 + xmod > CW->x2 || CW->y1 + y2 + ymod > CW->y2)
357     {
358         return;
359     }
360 
361     WDrwBox(x1 + CW->x1 + xmod, y1 + CW->y1 + ymod, x2 + CW->x1 + xmod, y2 + CW->y1 + ymod, Bdrt, Attr, 0);
362 }
363 
364 /*
365  *  WndGetRel; Converts absolute coordinates to coordinates relative
366  *  to the current window.
367  */
368 
WndGetRel(int x,int y,int * wx,int * wy)369 void WndGetRel(int x, int y, int *wx, int *wy)
370 {
371     int xmod, ymod;
372 
373     if (CW == NULL)
374     {
375         return;
376     }
377 
378     ymod = YMOD(CW);
379     xmod = XMOD(CW);
380 
381     *wx = x - (CW->x1 + xmod);
382     *wy = y - (CW->y1 + ymod);
383 }
384 
WndWidth(void)385 int WndWidth(void)
386 {
387     if (CW == NULL)
388     {
389         return 0;
390     }
391     return CW->x2 - CW->x1 - (XMOD(CW) * 2);
392 }
393 
394 /*
395  *  WndTitle; Writes a title to centre of the *current* window,
396  *  clearing whatever was there initially.
397  *
398  *  Caveats: Doesn't check to see if there is a border, only for the
399  *  type of border.
400  */
401 
WndTitle(const char * title,int Attr)402 void WndTitle(const char *title, int Attr)
403 {
404     int cntr;
405     int pos, i, len;
406     unsigned long ch;
407     int ymod;
408     int Bdrt = SBDR;
409     int m = 0;
410 
411     if (CW == NULL)
412     {
413         return;
414     }
415 
416     if (title == NULL)
417     {
418         title = "<-- null pointer passed -->";
419     }
420     cntr = (CW->x2 - CW->x1 + 1) / 2;
421     len = strlen(title);
422 
423     /* 'cause were writing on the border */
424     if (CW->flags & INSBDR)
425     {
426         ymod = 1;
427     }
428     else
429     {
430         ymod = 0;
431     }
432 
433     if (CheckMousePos(CW->x1, CW->y1, CW->x2, CW->y2))
434     {
435         m = 1;
436         MouseOFF();
437     }
438 
439     TTBeginOutput();
440 
441     if (CW->title)
442     {
443         if (!(CW->flags & NBDR))
444         {
445             if (CW->flags & SBDR)
446             {
447                 Bdrt = SBDR;
448             }
449             else
450             {
451                 Bdrt = DBDR;
452             }
453         }
454 
455         ch = MAKECELL(Bdr(Bdrt,1), CW->battr | F_ALTERNATE);
456         for (i = CW->x1 + 1; i < CW->x2; i++)
457         {
458             TTWriteStr(&ch, 1, CW->y1 + ymod, i);
459         }
460 
461         xfree(CW->title);
462     }
463 
464     pos = (cntr - (len / 2)) + CW->x1;
465     CW->title = xstrdup(title);
466 
467     TTScolor(Attr);
468     TTStrWr((unsigned char *)title, CW->y1 + ymod, pos, -1);
469 
470     if (m)
471     {
472         MouseON();
473     }
474 
475     TTEndOutput();
476 }
477 
478 /*
479  *  WndWriteStr; Writes a string to the (current) window, using a
480  *  zero-based origin.
481  *
482  *  Caveats: If string would write past end of line, it won't write
483  *  the string.
484  */
485 
WndWriteStr(int x,int y,int Attr,char * Str)486 void WndWriteStr(int x, int y, int Attr, char *Str)
487 {
488     int row, col, len;
489     int m = 0;
490     char *PrintStr = Str;
491 
492     if (Str == NULL)
493     {
494         return;
495     }
496 
497     len = strlen(Str);
498 
499 
500     if (CW == NULL)
501     {
502         return;
503     }
504 
505     /* row and col must be zero-based */
506     row = CW->y1 + y;
507     col = CW->x1 + x;
508 
509     if (x < 0 || y < 0)
510     {
511         return;
512     }
513 
514     if (!(CW->flags & NBDR))
515     {
516         /* check end-of-window overstep */
517         row += YMOD(CW);
518         col += XMOD(CW);
519         if (row >= CW->y2 || col > CW->x2 - XMOD(CW))
520         {
521             return;
522         }
523     }
524     else
525     {
526         if (row > CW->y2 || col > CW->x2)
527         {
528             return;
529         }
530     }
531 
532     if (CheckMousePos(col, row, col + len - 1, row))
533     {
534         m = 1;
535         MouseOFF();
536     }
537 
538     if ((col + len - 1) > CW->x2 - XMOD(CW))
539     {
540         len = ((CW->x2 - XMOD(CW)) - col + 1);
541         PrintStr = xmalloc(len + 1);
542         memcpy(PrintStr, Str, len);
543         PrintStr[len] = '\0';
544     }
545 
546     TTBeginOutput();
547 
548     TTScolor(Attr);
549     TTStrWr((unsigned char *)PrintStr, row, col, len);
550 
551     if (PrintStr != Str)
552     {
553         xfree(PrintStr);
554     }
555 
556     TTEndOutput();
557 
558     if (m)
559     {
560         MouseON();
561     }
562 }
563 
564 /*
565  *  WndPutsCen; Puts a string in the center of the window at the passed
566  *  line.
567  */
568 
WndPutsCen(int y,int attr,char * str)569 void WndPutsCen(int y, int attr, char *str)
570 {
571     int cntr;
572     int col, len;
573     int mod;
574 
575     if (CW == NULL)
576     {
577         return;
578     }
579 
580     if (str == NULL)
581     {
582         return;
583     }
584 
585     if (y < 0)
586     {
587         return;
588     }
589 
590     cntr = (CW->x2 - CW->x1 + 1) / 2;
591     mod = XMOD(CW);
592     len = strlen(str);
593 
594 
595     if (len > WndWidth())
596     {
597         col = 0;
598     }
599     else
600     {
601         col = cntr - (len / 2) - mod;
602     }
603     WndWriteStr(col, y, attr, str);
604 }
605 
606 /*
607  *  WndPrintf; Operates the same as printf(), except it does it to the
608  *  current window, using the passed parameters.
609  */
610 
WndPrintf(int x,int y,int attr,char * str,...)611 int WndPrintf(int x, int y, int attr, char *str, ...)
612 {
613     int rc;
614     va_list params;
615     va_start(params, str);
616     rc = vsprintf(line, str, params);
617     WndWriteStr(x, y, attr, line);
618     return rc;
619 }
620 
621 /*
622  *  WndPutsn; Puts len of str onto the current window.
623  */
624 
WndPutsn(int x,int y,int len,int attr,char * str)625 void WndPutsn(int x, int y, int len, int attr, char *str)
626 {
627     char *s = str, *c = line;
628     int i = 0;
629 
630     if (x < 0 || y < 0 || len < 1)
631     {
632         return;
633     }
634     if (len > 254)
635     {
636         len = 254;
637     }
638     if (s != NULL)
639     {
640         i = strlen(s);
641         if (i > len)
642         {
643             i = len;
644         }
645         memcpy(c, s, i);
646     }
647     if (i < len)
648     {
649         memset(c + i, ' ', len - i);
650     }
651     c[len] = '\0';
652     WndWriteStr(x, y, attr, line);
653 }
654 
655 /*
656  *  WndScroll; Scrolls a window at the specified cooridiates using a
657  *  zero-based origin.
658  *
659  */
660 
WndScroll(int x1,int y1,int x2,int y2,int dir)661 void WndScroll(int x1, int y1, int x2, int y2, int dir)
662 {
663     int xmod, ymod;
664     int m = 0;
665 
666     if (CW == NULL)
667     {
668         return;
669     }
670 
671     if (x1 < 0) x1 = 0;
672     if (y1 < 0) y1 = 0;
673     if (x2 < x1 || y2 < y1) return;
674 
675     xmod = XMOD(CW);
676     ymod = YMOD(CW);
677 
678     if (CheckMousePos(CW->x1 + x1 + xmod, CW->y1 + y1 + ymod, CW->x2 + x2 + xmod, CW->y2 + y2 + ymod))
679     {
680         m = 1;
681         MouseOFF();
682     }
683     TTBeginOutput();
684     TTScolor(CW->wattr);
685     TTScroll(CW->x1 + x1 + xmod, CW->y1 + y1 + ymod, CW->x1 + x2 + xmod,
686              CW->y1 + y2 + ymod, 1, dir);
687     TTEndOutput();
688 
689     if (m)
690     {
691         MouseON();
692     }
693 }
694 
695 /*
696  *  WndCurr; Makes the passed window the current window.
697  *
698  *  Caveats: The windowing system doesn't keep track of the windows
699  *  that exist - the caller must do that.
700  */
701 
WndCurr(WND * hWnd)702 void WndCurr(WND * hWnd)
703 {
704     if (CW == hWnd || hWnd == NULL)
705     {
706         return;
707     }
708     CW = hWnd;
709 }
710 
711 /*
712  *  WndTop; Returns the current window recognized by the windowing system.
713  */
714 
WndTop(void)715 WND *WndTop(void)
716 {
717     if (CW != NULL)
718     {
719         return CW;
720     }
721     else
722     {
723         return NULL;
724     }
725 }
726 
727 /*
728  *  WndPutc; Puts a char anywhere on the window, ignoring borders, etc.
729  *  Puts it at the current cursor position (virtual or real).
730  *
731  *  Caveats: The cursor may not even be on the window, but it doesn't
732  *  care.  :-)
733  */
734 
WndPutc(int Ch,int attr)735 void WndPutc(int Ch, int attr)
736 {
737     if (CW == NULL)
738     {
739         return;
740     }
741     MouseOFF();
742     TTScolor(attr);
743     TTPutChr(Ch);
744     MouseON();
745 }
746 
747 /*
748  *  WndGotoXY; Goes to the passed coordinates, zero-based, starting
749  *  from any borders on the window.
750  *
751  *  Caveats: No checks for validity of arguments.
752  */
753 
WndGotoXY(int x,int y)754 void WndGotoXY(int x, int y)
755 {
756     int xmod, ymod;
757 
758     if (CW == NULL)
759     {
760         return;
761     }
762 
763     xmod = XMOD(CW);
764     ymod = YMOD(CW);
765 
766     TTgotoxy(CW->y1 + y + ymod, CW->x1 + x + xmod);
767 }
768 
769 /*
770  *  WndClear; Clears the passed coordinates with the passed attribute
771  *  in the current window.
772  *
773  *  Caveats: No checks for validity of arguments.
774  */
775 
WndClear(int x1,int y1,int x2,int y2,int attr)776 void WndClear(int x1, int y1, int x2, int y2, int attr)
777 {
778     int xmod, ymod, m = 0;
779 
780     if (CW == NULL)
781     {
782         return;
783     }
784 
785     xmod = XMOD(CW);
786     ymod = YMOD(CW);
787 
788     if (CheckMousePos(CW->x1 + x1 + xmod, CW->y1 + y1 + ymod, CW->x2 + x2 + xmod, CW->y2 + y2 + ymod))
789     {
790         m = 1;
791         MouseOFF();
792     }
793     TTScolor(attr);
794     TTClear(CW->x1 + x1 + xmod, CW->y1 + y1 + ymod, CW->x1 + x2 + xmod, CW->y1 + y2 + ymod);
795     if (m)
796     {
797         MouseON();
798     }
799 }
800 
801 /*
802  *  WndClearLine; Clears the passed line in the current window.
803  */
804 
WndClearLine(int y,int Att)805 void WndClearLine(int y, int Att)
806 {
807     if (CW == NULL)
808     {
809         return;
810     }
811     WndClear(0, y, CW->x2 - CW->x1 - (XMOD(CW) * 2), y, Att);
812 }
813 
814 /*
815  *  WndFillField; Fills in an edit-field region with char.
816  */
817 
WndFillField(int x,int y,int len,unsigned char ch,int Attr)818 void WndFillField(int x, int y, int len, unsigned char ch, int Attr)
819 {
820     if (len > sizeof(line) - 1)
821     {
822         len = sizeof(line) - 1;
823     }
824     memset(line, ch, len);
825     *(line + len - 1) = '\0';
826     WndWriteStr(x, y, Attr, line);
827 }
828 
829 /*
830  *  WndGetLine; Gets a string from the user on the current window at
831  *  the passed coordinates.  Passes mouse events not on itself back to
832  *  the caller via the extra parameters.
833  */
834 
WndGetLine(int x,int y,int len,char * buf,int Attr,int * pos,int nokeys,int fil,int disp,EVT * ev)835 int WndGetLine(int x, int y, int len, char *buf, int Attr, int *pos, int nokeys, int fil, int disp, EVT * ev)
836 {
837     EVT event;
838     int done = 0;
839     int row = y, col = x;
840     int xmod, ymod, i;
841     unsigned int ch = 0;
842     unsigned char fill;
843 
844     fill= (fil) ? SC13 : (unsigned char) ' ';
845 
846     if (CW == NULL)
847     {
848         return 0;
849     }
850 
851     if (x < 0) x = 0;
852     if (y < 0) y = 0;
853 
854     if (disp)
855     {
856         TTBeginOutput();
857         WndFillField(col, row, len + 1, fill, Attr | F_ALTERNATE);
858         WndPutsn(col, row, len, Attr, buf);
859         TTEndOutput();
860     }
861 
862     xmod = XMOD(CW);
863     ymod = YMOD(CW);
864 
865     i = *pos;
866 
867     TTCurSet(1);
868 
869     while (!done)
870     {
871         WndGotoXY(i + col, row);
872         ch = MnuGetMsg(&event, 0);
873         switch (event.msgtype)
874         {
875         case WND_WM_MOUSE:
876         case WND_WM_COMMAND:
877             {
878                 int p1 = event.x, p2 = event.y;
879                 if (p1 < CW->x1 + xmod + x || p1 > CW->x1 + xmod + x + len - 1 || p2 != CW->y1 + ymod + y)
880                 {
881                     done = TRUE;
882                     break;
883                 }
884             }
885             break;
886 
887         case WND_WM_CHAR:
888             switch (ch)
889             {
890             case Key_Up:
891             case Key_Dwn:
892                 done = TRUE;
893                 break;
894 
895             case Key_Lft:
896                 if (i > 0)
897                 {
898                     i--;
899                 }
900                 break;
901 
902             case Key_Rgt:
903                 if (i < strlen(buf))
904                 {
905                     i++;
906                 }
907                 break;
908 
909             case Key_A_X:
910                 memset(buf, 0, len);
911                 i = 0;
912                 break;
913 
914             case Key_BS:
915                 if (i > 0)
916                 {
917                     TTBeginOutput();
918                     if (i < strlen(buf))
919                     {
920                         memmove(buf + i - 1, buf + i, strlen(buf + i) + 1);
921                         i--;
922                         WndWriteStr(col + i, row, Attr, buf + i);
923                         WndPrintf(col + strlen(buf), row, Attr | F_ALTERNATE,
924                                   "%c", fill);
925                     }
926                     else
927                     {
928                         i--;
929                         *(buf + i) = '\0';
930                         WndGotoXY(i + col, row);
931                         WndPutc(fill, Attr | F_ALTERNATE);
932                     }
933                     TTEndOutput();
934                 }
935                 break;
936 
937             case Key_Del:
938                 if (i < strlen(buf))
939                 {
940                     TTBeginOutput();
941                     memmove(buf + i, buf + i + 1, strlen(buf + i + 1) + 1);
942                     WndWriteStr(col + i, row, Attr, buf + i);
943                     WndPrintf(col + strlen(buf), row, Attr | F_ALTERNATE,
944                               "%c", fill);
945                     TTEndOutput();
946                 }
947                 break;
948 
949             case Key_End:
950                 i = strlen(buf);
951                 break;
952 
953             case Key_Home:
954                 i = 0;
955                 break;
956 
957             case Key_Ent:
958                 done = 1;
959                 break;
960 
961             case Key_Esc:
962                 done = 2;
963                 break;
964 
965             default:
966                 if (ch > 0 && ch < 256 && i < len && strlen(buf) < len)
967                 {
968                     TTBeginOutput();
969                     if (nokeys)
970                     {
971                         strcpy(buf, "");
972                         WndFillField(col, row, len + 1, fill,
973                                      Attr | F_ALTERNATE);
974                         i = 0;
975                         WndGotoXY(i + col, row);
976                     }
977                     if (i < strlen(buf))
978                     {
979                         memmove(buf + i + 1, buf + i, strlen(buf + i) + 1);
980                         *(buf + i) = (char)ch;
981                         WndWriteStr(col + i, row, Attr, buf + i);
982                         i++;
983                     }
984                     else
985                     {
986                         *(buf + i) = (char)ch;
987                         *(buf + i + 1) = '\0';
988                         WndPutc((unsigned char)ch, Attr);
989                         i++;
990                     }
991                     TTEndOutput();
992                 }
993                 else
994                 {
995                    done = 1;
996                 }
997                 break;
998             }
999             break;
1000         }
1001         nokeys = 0;
1002     }
1003     TTCurSet(0);
1004 
1005     if (ev != NULL)
1006     {
1007         *ev = event;
1008     }
1009 
1010     *pos = i;
1011     return (int)ch;
1012 }
1013