syslinux-3.08-2 sources from FC4
[bootcd.git] / syslinux / menu / libmenu / tui.c
1 /* -*- c -*- ------------------------------------------------------------- *
2  *   
3  *   Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8  *   Boston MA 02111-1307, USA; either version 2 of the License, or
9  *   (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12
13 #include <string.h>
14 #include <com32.h>
15 #include "tui.h"
16 #include "syslnx.h"
17 #include "com32io.h"
18 #include "scancodes.h"
19 #include <stdlib.h>
20
21 com32sys_t inreg,outreg; // Global register sets for use
22
23 char bkspstr[] = " \b$";
24 char eolstr[] = "\n$";
25 #define GETSTRATTR 0x07
26
27 // Reads a line of input from stdin. Replace CR with NUL byte
28 // password <> 0 implies not echoed on screen
29 // showoldvalue <> 0 implies currentvalue displayed first
30 // If showoldvalue <> 0 then caller responsibility to ensure that
31 // str is NULL terminated.
32 void getuserinput(char *stra, unsigned int size, unsigned int password, 
33   unsigned int showoldvalue)
34 {
35     unsigned char c,scan;
36     char *p,*q; // p = current char of string, q = tmp
37     char *last; // The current last char of string
38     char *str; // pointer to string which is going to be allocated
39     char page;
40     char row,col;
41     char start,end; // Cursor shape
42     char fudge; // How many chars should be removed from output
43     char insmode; // Are we in insert or overwrite
44
45     page = getdisppage();
46     getpos(&row,&col,page); // Get current position
47     getcursorshape(&start,&end);
48     insmode = 1;
49
50     str = (char *)malloc(size+1); // Allocate memory to store user input
51     memset(str,0,size+1); // Zero it out
52     if (password != 0) showoldvalue = 0; // Password's never displayed
53
54     if (showoldvalue != 0) strcpy(str,stra); // If show old value copy current value
55
56     last = str;
57     while (*last) {last++;} // Find the terminating null byte
58     p = str+ strlen(str);
59
60     if (insmode == 0)
61        setcursorshape(1,7); // Block cursor
62     else setcursorshape(6,7); // Normal cursor
63
64     // Invariants: p is the current char
65     // col is the corresponding column on the screen
66     if (password == 0) // Not a password, print initial value
67     { 
68        gotoxy(row,col,page);
69        csprint(str,GETSTRATTR);
70     }
71     while (1) { // Do forever
72       c = inputc(&scan);
73       if (c == '\r') break; // User hit Enter getout of loop
74       if (scan == ESCAPE) // User hit escape getout and nullify string
75       { *str = 0;
76         break;
77       }
78       fudge = 0;
79         // if scan code is regognized do something 
80         // else if char code is recognized do something
81         // else ignore
82       switch(scan) {
83         case HOMEKEY:
84              p = str;
85              break;
86         case ENDKEY:
87              p = last;
88              break;
89         case LTARROW:
90              if (p > str) p--;
91              break;
92         case CTRLLT: 
93              if (p==str) break;
94              if (*p == ' ') 
95                 while ((p > str) && (*p == ' ')) p--;
96              else {
97                 if (*(p-1) == ' ') {
98                    p--; 
99                    while ((p > str) && (*p == ' ')) p--;
100                 }
101              }
102              while ((p > str) && ((*p == ' ') || (*(p-1) != ' '))) p--;
103              break;
104         case RTARROW:
105              if (p < last) p++;
106              break;
107         case CTRLRT: 
108              if (*p==0) break; // At end of string
109              if (*p != ' ') 
110                 while ((*p!=0) && (*p != ' ')) p++;
111              while ((*p!=0) && ((*p == ' ') && (*(p+1) != ' '))) p++;
112              if (*p==' ') p++;
113              break;
114         case DELETE:
115              q = p;
116              while (*(q+1)) {*q = *(q+1); q++; }
117              if (last > str) last--;
118              fudge = 1;
119              break;
120         case INSERT:
121            insmode = 1-insmode; // Switch mode
122            if (insmode == 0)
123               setcursorshape(1,7); // Block cursor
124            else setcursorshape(6,7); // Normal cursor
125            break;
126
127         default: // Unrecognized scan code, look at the ascii value
128           switch (c) {
129           case '\b': // Move over by one
130               q=p;
131               while ( q <= last ) { *(q-1)=*q; q++;}
132               if (last > str) last--;
133               if (p > str) p--;
134               fudge = 1;
135               break;
136           case '\x15':          /* Ctrl-U: kill input */
137               fudge = last-str;
138               while ( p > str ) *p--=0;
139               p = str; *p=0; last = str;
140               break;
141           default: // Handle insert and overwrite mode
142               if ((c >= ' ') && (c < 128) && 
143                   ((unsigned int)(p-str) < size-1) ) {
144                 if (insmode == 0) { // Overwrite mode
145                   if (p==last) last++;
146                   *last = 0;
147                   *p++ = c;
148                 } else {  // Insert mode
149                   if (p==last) { // last char
150                      last++;
151                      *last=0;
152                      *p++=c;
153                   } else { // Non-last char
154                      q=last++;
155                      while (q >= p) { *q=*(q-1); q--;}
156                      *p++=c;
157                   }
158                 }
159               }
160               else beep();
161           }
162           break;
163         }
164         // Now the string has been modified, print it
165         if (password == 0) {
166           gotoxy(row,col,page);
167           csprint(str,GETSTRATTR);
168           if (fudge > 0) cprint(' ',GETSTRATTR,fudge,page);
169           gotoxy(row,col+(p-str),page);
170         }
171       }
172     *p = '\0';
173     if (password == 0) csprint("\r\n",GETSTRATTR);
174     setcursorshape(start,end); // Block cursor
175     // If user hit ESCAPE so return without any changes
176     if (scan != ESCAPE) strcpy(stra,str);
177     free(str);
178 }
179
180 /* Print a C string (NUL-terminated) */
181 void cswprint(const char *str,char attr,char left)
182 {
183     char page = getdisppage();
184     char newattr=0,cha,chb;
185     char row,col;
186     char nr,nc;
187
188     nr = getnumrows();
189     nc = getnumcols();
190     getpos(&row,&col,page);
191     while ( *str ) {
192       switch (*str) 
193         {
194         case '\b':
195           --col;
196           break;
197         case '\n':
198           ++row;
199           col = left;
200           break;
201         case '\r':
202           //col=left;
203           break;
204         case BELL: // Bell Char
205           beep();
206           break;
207         case CHRELATTR: // change attribute (relatively)
208         case CHABSATTR: // change attribute (absolute)
209           cha = *(str+1);
210           chb = *(str+2);
211           if ((((cha >= '0') && (cha <= '9')) || 
212                ((cha >= 'A') && (cha <= 'F'))) &&
213               (((chb >= '0') && (chb <= '9')) || 
214                ((chb >= 'A') && (chb <= 'F')))) // Next two chars are legal
215             {
216               if ((cha >= 'A') && (cha <= 'F'))
217                 cha = cha - 'A'+10;
218               else cha = cha - '0';
219               if ((chb >= 'A') && (chb <= 'F'))
220                 chb = chb - 'A'+10;
221               else chb = chb - '0';
222               newattr = (cha << 4) + chb;
223               attr = (*str == CHABSATTR ? newattr : attr ^ newattr);
224               str += 2; // Will be incremented again later
225             }
226           break;
227         default:
228           putch(*str, attr, page);
229           ++col;
230         }
231       if (col >= nc)
232         {
233           ++row;
234           col=left;
235         }
236       if (row > nr)
237         {
238           scrollup();
239           row= nr;
240         }
241       gotoxy(row,col,page);
242       str++;
243     }
244 }
245
246 void clearwindow(char top, char left, char bot, char right, char page, char fillchar, char fillattr)
247 {
248     char x;
249     for (x=top; x < bot+1; x++)
250     {
251         gotoxy(x,left,page);
252         cprint(fillchar,fillattr,right-left+1,page);
253     }
254 }
255
256 void cls(void)
257 {
258   unsigned char dp = getdisppage();
259   gotoxy(0,0,dp);
260   cprint(' ',GETSTRATTR,(1+getnumrows())*getnumcols(),dp);
261 }
262
263 //////////////////////////////Box Stuff
264
265 // This order of numbers must match
266 // the values of BOX_TOPLEFT,... in the header file
267
268 unsigned char SINSIN_CHARS[] = {218,192,191,217, //Corners
269                               196,179, // Horiz and Vertical
270                               195,180,194,193,197}; // Connectors & Middle
271
272 unsigned char DBLDBL_CHARS[] = {201,200,187,188,  // Corners
273                               205,186, // Horiz and Vertical
274                               199,182,203,202,206}; // Connectors & Middle
275
276 unsigned char SINDBL_CHARS[] =  {214,211,183,189, // Corners
277                                  196,186, // Horiz & Vert
278                                  199,182,210,208,215}; // Connectors & Middle
279
280 unsigned char DBLSIN_CHARS[] = {213,212,184,190, // Corners
281                                 205,179, // Horiz & Vert
282                                 198,181,209,207,216}; // Connectors & Middle
283
284 unsigned char * getboxchars(boxtype bt)
285 {
286    switch (bt)
287    {
288      case BOX_SINSIN: 
289           return SINSIN_CHARS;
290           break;
291      case BOX_DBLDBL:
292           return DBLDBL_CHARS;
293           break;
294      case BOX_SINDBL:
295           return SINDBL_CHARS;
296           break;
297      case BOX_DBLSIN:
298           return DBLSIN_CHARS;
299           break;
300      default:
301           return SINSIN_CHARS;
302           break;
303    }
304    return SINSIN_CHARS;
305 }
306
307 // Draw box and lines
308 void drawbox(char top,char left,char bot, char right, 
309              char page, char attr,boxtype bt)
310 {
311    unsigned char *box_chars; // pointer to array of box chars
312    unsigned char x;
313     
314   box_chars = getboxchars(bt);
315   // Top border
316   gotoxy(top,left,page);
317   cprint(box_chars[BOX_TOPLEFT],attr,1,page);
318   gotoxy(top,left+1,page);
319   cprint(box_chars[BOX_TOP],attr,right-left,page);
320   gotoxy(top,right,page);
321   cprint(box_chars[BOX_TOPRIGHT],attr,1,page);
322   // Bottom border
323   gotoxy(bot,left,page);
324   cprint(box_chars[BOX_BOTLEFT],attr,1,page);
325   gotoxy(bot,left+1,page);
326   cprint(box_chars[BOX_BOT],attr,right-left,page);
327   gotoxy(bot,right,page);
328   cprint(box_chars[BOX_BOTRIGHT],attr,1,page);
329   // Left & right borders
330   for (x=top+1; x < bot; x++)
331     {
332       gotoxy(x,left,page);
333       cprint(box_chars[BOX_LEFT],attr,1,page);
334       gotoxy(x,right,page);
335       cprint(box_chars[BOX_RIGHT],attr,1,page);
336     }
337 }
338
339 void drawhorizline(char top, char left, char right, char page, char attr, 
340                    boxtype bt, char dumb)
341 {
342   unsigned char start,end;
343   unsigned char *box_chars = getboxchars(bt);
344   if (dumb==0) {
345     start = left+1;
346     end = right-1;
347   } else {
348     start = left;
349     end = right;
350   }
351   gotoxy(top,start,page);
352   cprint(box_chars[BOX_HORIZ],attr,end-start+1,page);
353   if (dumb == 0)
354   {
355     gotoxy(top,left,page);
356     cprint(box_chars[BOX_LTRT],attr,1,page);
357     gotoxy(top,right,page); 
358     cprint(box_chars[BOX_RTLT],attr,1,page);
359   }
360 }