]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - gnu/lib/libdialog/kernel.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / gnu / lib / libdialog / kernel.c
1 /*
2  *  dialog - Display simple dialog boxes from shell scripts
3  *
4  *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation; either version 2
9  *  of the License, or (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  *
21  *  HISTORY:
22  *
23  *  17/12/93 - Version 0.1 released.
24  *
25  *  19/12/93 - menu will now scroll if there are more items than can fit
26  *             on the screen.
27  *           - added 'checklist', a dialog box with a list of options that
28  *             can be turned on or off. A list of options that are on is
29  *             returned on exit.
30  *
31  *  20/12/93 - Version 0.15 released.
32  *
33  *  29/12/93 - Incorporated patch from Patrick J. Volkerding
34  *             (volkerdi@mhd1.moorhead.msus.edu) that made these changes:
35  *             - increased MAX_LEN to 2048
36  *             - added 'infobox', equivalent to a message box without pausing
37  *             - added option '--clear' that will clear the screen
38  *             - Explicit line breaking when printing prompt text can be
39  *               invoked by real newline '\n' besides the string "\n"
40  *           - an optional parameter '--title <string>' can be used to
41  *             specify a title string for the dialog box
42  *
43  *  03/01/94 - added 'textbox', a dialog box for displaying text from a file.
44  *           - Version 0.2 released.
45  *
46  *  04/01/94 - some fixes and improvements for 'textbox':
47  *             - fixed a bug that will cause a segmentation violation when a
48  *               line is longer than MAX_LEN characters. Lines will now be
49  *               truncated if they are longer than MAX_LEN characters.
50  *             - removed wrefresh() from print_line(). This will increase
51  *               efficiency of print_page() which calls print_line().
52  *             - display current position in the form of percentage into file.
53  *           - Version 0.21 released.
54  *
55  *  05/01/94 - some changes for faster screen update.
56  *
57  *  07/01/94 - much more flexible color settings. Can use all 16 colors
58  *             (8 normal, 8 highlight) of the Linux console.
59  *
60  *  08/01/94 - added run-time configuration using configuration file.
61  *
62  *  09/01/94 - some minor bug fixes and cleanups for menubox, checklist and
63  *             textbox.
64  *
65  *  11/01/94 - added a man page.
66  *
67  *  13/01/94 - some changes for easier porting to other Unix systems (tested
68  *             on Ultrix, SunOS and HPUX)
69  *           - Version 0.3 released.
70  *
71  *  08/06/94 - Patches by Stuart Herbert - S.Herbert@shef.ac.uk
72  *             Fixed attr_clear and the textbox stuff to work with ncurses 1.8.5
73  *             Fixed the wordwrap routine - it'll actually wrap properly now
74  *             Added a more 3D look to everything - having your own rc file could
75  *               prove 'interesting' to say the least :-)
76  *             Added radiolist option
77  *           - Version 0.4 released.
78  */
79
80 #define __DIALOG_MAIN__
81
82 #include <dialog.h>
83 #include "dialog.priv.h"
84 #ifdef HAVE_NCURSES
85 #include "colors.h"
86 #endif
87
88 /* These are two "secret" globals that can be fiddled to make a dialog
89  * come up someplace other than a "centered" calculation for X,Y
90  */
91 int DialogX, DialogY;
92
93 /* This "secret" global allows you to change the behavior of an input field */
94 int DialogInputAttrs;
95
96 /*
97  * Do some initialization for dialog
98  */
99 void init_dialog(void)
100 {
101 #if defined(LOCALE)
102   (void) setlocale(LC_ALL, "");
103 #endif
104
105 #ifdef HAVE_NCURSES
106   if (parse_rc() == -1)    /* Read the configuration file */
107     exit(-1);
108 #endif
109
110   if (initscr() == NULL) { /* Init curses */
111     fprintf(stderr, "\nCurses initialization error.\n");
112     exit(-1);
113   }
114   keypad(stdscr, TRUE);
115   cbreak();
116   noecho();
117
118 #ifdef HAVE_NCURSES
119   if (use_colors || use_shadow)    /* Set up colors */
120     color_setup();
121 #endif
122
123   /* Set screen to screen attribute */
124   dialog_clear_norefresh();
125   DialogX = DialogY = 0;
126 }
127 /* End of init_dialog() */
128
129
130 #ifdef HAVE_NCURSES
131 /*
132  * Setup for color display
133  */
134 void color_setup(void)
135 {
136   int i;
137
138   if (has_colors()) {    /* Terminal supports color? */
139     start_color();
140
141     /* Initialize color pairs */
142     for (i = 0; i < ATTRIBUTE_COUNT; i++)
143       init_pair(i+1, color_table[i][0], color_table[i][1]);
144
145     /* Setup color attributes */
146     for (i = 0; i < ATTRIBUTE_COUNT; i++)
147       attributes[i] = C_ATTR(color_table[i][2], i+1);
148   }
149 }
150 /* End of color_setup() */
151 #endif
152
153
154 /*
155  * Set window to attribute 'attr'
156  */
157 void attr_clear(WINDOW *win, int height, int width, chtype attr)
158 {
159   int i, j;
160
161   wattrset(win, attr);    /* Set window to attribute 'attr' */
162   for (i = 0; i < height; i++) {
163     wmove(win, i, 0);
164     for (j = 0; j < width; j++)
165       waddch(win, ' ');
166   }
167 }
168 /* End of attr_clear() */
169
170
171 /*
172  * Print a string of text in a window, automatically wrap around to the
173  * next line if the string is too long to fit on one line. Note that the
174  * string may contain "\n" to represent a newline character or the real
175  * newline '\n', but in that case, auto wrap around will be disabled.
176  */
177 void print_autowrap(WINDOW *win, unsigned char *prompt, int height, int width, int maxwidth, int y, int x, int center, int rawmode)
178 {
179   int cur_x, cur_y, i;
180   unsigned char tempstr[MAX_LEN+1], *word, *tempptr, *tempptr1;
181   chtype ostuff[132], attrs = 0, init_bottom = 0;
182
183   wsetscrreg(win, y, height);
184   getyx(win, cur_y, cur_x);
185
186   strncpy(tempstr, prompt, MAX_LEN);
187   tempstr[MAX_LEN] = '\0';
188   if ((!rawmode && strstr(tempstr, "\\n") != NULL) ||
189       (strchr(tempstr, '\n') != NULL)) {    /* Prompt contains "\n" or '\n' */
190     word = tempstr;
191     while (1) {
192       tempptr = rawmode ? NULL : strstr(word, "\\n");
193       tempptr1 = strchr(word, '\n');
194       if (tempptr == NULL && tempptr1 == NULL)
195         break;
196       else if (tempptr == NULL) {    /* No more "\n" */
197         tempptr = tempptr1;
198         tempptr[0] = '\0';
199       }
200       else if (tempptr1 == NULL) {    /* No more '\n' */
201         tempptr[0] = '\0';
202         tempptr++;
203       }
204       else {    /* Prompt contains both "\n" and '\n' */
205         if (strlen(tempptr)-2 < strlen(tempptr1)-1) {
206           tempptr = tempptr1;
207           tempptr[0] = '\0';
208         }
209         else {
210           tempptr[0] = '\0';
211           tempptr++;
212         }
213       }
214
215       waddstr(win, word);
216       word = tempptr + 1;
217       if (++cur_y > height) {
218         cur_y--;
219         if (!init_bottom) {
220           for (i = 0; i < x; i++)
221             ostuff[i] = mvwinch(win, cur_y, i);
222           for (i = width; i < maxwidth; i++)
223             ostuff[i] = mvwinch(win, cur_y, i);
224           attrs = getattrs(win);
225           init_bottom = 1;
226         }
227         scrollok(win, TRUE);
228         scroll(win);
229         scrollok(win, FALSE);
230         wmove(win, cur_y, 0);
231         for (i = 0; i < x; i++) {
232           wattrset(win, ostuff[i]&A_ATTRIBUTES);
233           waddch(win, ostuff[i]);
234         }
235         wattrset(win, attrs);
236         for ( ; i < width; i++)
237           waddch(win, ' ');
238         for ( ; i < maxwidth; i++) {
239           wattrset(win, ostuff[i]&A_ATTRIBUTES);
240           waddch(win, ostuff[i]);
241         }
242         wattrset(win, attrs);
243         wrefresh(win);
244       }
245       wmove(win, cur_y, cur_x = x);
246     }
247     waddstr(win, word);
248   }
249   else if (center && strlen(tempstr) <= width-x*2) {    /* If prompt is short */
250     wmove(win, cur_y, (width - strlen(tempstr)) / 2);
251     waddstr(win, tempstr);
252   }
253   else if (!center && strlen(tempstr) <= width-cur_x) {    /* If prompt is short */
254     waddstr(win, tempstr);
255   }
256   else {
257     char *p = tempstr;
258
259     /* Print prompt word by word, wrap around if necessary */
260     while ((word = strsep(&p, "\t\n ")) != NULL) {
261       int loop;
262       unsigned char sc;
263
264       if (*word == '\0')
265         continue;
266       do {
267         loop = 0;
268         if (cur_x+strlen(word) >= width+1) {    /* wrap around to next line */
269           if (x+strlen(word) >= width+1) {
270             sc = word[width-cur_x-1];
271             word[width-cur_x-1] = '\0';
272             wmove(win, cur_y, cur_x);
273             waddstr(win, word);
274             word[width-cur_x-1] = sc;
275             word += width-cur_x-1;
276             getyx(win, cur_y, cur_x);
277             loop = 1;
278           }
279           cur_y++;
280           cur_x = x;
281           if (cur_y > height) {
282             cur_y--;
283             if (!init_bottom) {
284               for (i = 0; i < x; i++)
285                 ostuff[i] = mvwinch(win, cur_y, i);
286               for (i = width; i < maxwidth; i++)
287                 ostuff[i] = mvwinch(win, cur_y, i);
288               attrs = getattrs(win);
289               init_bottom = 1;
290             }
291             scrollok(win, TRUE);
292             scroll(win);
293             scrollok(win, FALSE);
294             wmove(win, cur_y, 0);
295             for (i = 0; i < x; i++) {
296               wattrset(win, ostuff[i]&A_ATTRIBUTES);
297               waddch(win, ostuff[i]);
298             }
299             wattrset(win, attrs);
300             for ( ; i < width; i++)
301               waddch(win, ' ');
302             for ( ; i < maxwidth; i++) {
303               wattrset(win, ostuff[i]&A_ATTRIBUTES);
304               waddch(win, ostuff[i]);
305             }
306             wattrset(win, attrs);
307             wrefresh(win);
308           }
309         }
310       }
311       while(loop);
312       wmove(win, cur_y, cur_x);
313       waddstr(win, word);
314       getyx(win, cur_y, cur_x);
315       cur_x++;
316     }
317   }
318 }
319 /* End of print_autowrap() */
320
321
322 /*
323  * Print a button
324  */
325 void print_button(WINDOW *win, unsigned char *label, int y, int x, int selected)
326 {
327   int i, temp;
328
329   wmove(win, y, x);
330   wattrset(win, selected ? button_active_attr : button_inactive_attr);
331   waddstr(win, selected ? "[" : " ");
332   temp = strspn(label, " ");
333   label += temp;
334   for (i = 0; i < temp; i++)
335     waddch(win, ' ');
336   wattrset(win, selected ? button_key_active_attr : button_key_inactive_attr);
337   waddch(win, label[0]);
338   wattrset(win, selected ? button_active_attr : button_inactive_attr);
339   waddstr(win, label+1);
340   waddstr(win, selected ? "]" : " ");
341   wmove(win, y, x+temp+1);
342 }
343 /* End of print_button() */
344
345
346 /*
347  * Draw a rectangular box with line drawing characters
348  */
349 void draw_box(WINDOW *win, int y, int x, int height, int width, chtype box, chtype border)
350 {
351   int i, j;
352
353   wattrset(win, 0);
354   for (i = 0; i < height; i++) {
355     wmove(win, y + i, x);
356     for (j = 0; j < width; j++)
357       if (!i && !j)
358         waddch(win, border | ACS_ULCORNER);
359       else if (i == height-1 && !j)
360         waddch(win, border | ACS_LLCORNER);
361       else if (!i && j == width-1)
362         waddch(win, box | ACS_URCORNER);
363       else if (i == height-1 && j == width-1)
364         waddch(win, box | ACS_LRCORNER);
365       else if (!i)
366         waddch(win, border | ACS_HLINE);
367       else if (i == height-1)
368         waddch(win, box | ACS_HLINE);
369       else if (!j)
370         waddch(win, border | ACS_VLINE);
371       else if (j == width-1)
372         waddch(win, box | ACS_VLINE);
373       else
374         waddch(win, box | ' ');
375   }
376 }
377 /* End of draw_box() */
378
379
380 #ifdef HAVE_NCURSES
381 /*
382  * Draw shadows along the right and bottom edge to give a more 3D look
383  * to the boxes
384  */
385 void draw_shadow(WINDOW *win, int y, int x, int height, int width)
386 {
387   int i,sx,sy;
388   chtype attrs;
389
390   if (has_colors()) {    /* Whether terminal supports color? */
391     getbegyx(win,sy,sx);
392     attrs = getattrs(win);
393     if (y+height < getmaxy(win)) {
394         /* small touch */
395         wattrset(win, A_INVIS);
396         wmove(win, y + height, x + 2);
397         for (i = 0; i < width; i++)
398             if (i+x+2 < getmaxx(win))
399                waddch(win, ' ');
400         /* end touch */
401         wattrset(win, shadow_attr);
402         wmove(win, y + height, x + 2);
403         for (i = 0; i < width; i++)
404             if (i+x+2 < getmaxx(win))
405                waddch(win, mvwinch(newscr, sy+y+height, sx+x+2+i) & A_CHARTEXT);
406     }
407     if (x+width < getmaxx(win)) {
408         for (i = y + 1; i < y + height + 1; i++) {
409           if (i < getmaxy(win)) {
410               /* small touch */
411               wattrset(win, A_INVIS);
412               wmove(win, i, x + width);
413               waddch(win, ' ');
414               if (x+width+1 < getmaxx(win))
415                     waddch(win, ' ');
416               /* end touch */
417               wattrset(win, shadow_attr);
418               wmove(win, i, x + width);
419               waddch(win, mvwinch(newscr, sy+i, sx+x+width) & A_CHARTEXT);
420               if (x+width+1 < getmaxx(win))
421                     waddch(win, mvwinch(newscr, sy+i, sx+x+width+1) & A_CHARTEXT);
422           }
423         }
424     }
425     wattrset(win, attrs);
426     wnoutrefresh(win);
427   }
428 }
429 /* End of draw_shadow() */
430 #endif
431
432 void dialog_clear_norefresh(void)
433 {
434     attr_clear(stdscr, LINES, COLS, screen_attr);
435     touchwin(stdscr);
436     wnoutrefresh(stdscr);
437 }
438
439 void dialog_clear(void)
440 {
441     dialog_clear_norefresh();
442     doupdate();
443 }
444
445 void dialog_update(void)
446 {
447     refresh();
448 }
449
450 void end_dialog(void)
451 {
452     endwin();
453 }
454
455 int strwidth(const char *p)
456 {
457         int i = 0, len, incr;
458         const char *start, *s, *s1, *s2;
459
460         for (start = s = p; ; start = (s += incr)) {
461                 s1 = strchr(s, '\n');
462                 s2 = strstr(s, "\\n");
463                 if (s2 == NULL)
464                         s = s1;
465                 else if (s1 == NULL)
466                         s = s2;
467                 else
468                         s = MIN(s1, s2);
469                 if (s == NULL)
470                         break;
471                 incr = 1 + (s == s2);
472                 len = s - start;
473                 if (len > i)
474                         i = len;
475         }
476         len = strlen(start);
477         if (len > i)
478                 i = len;
479         return i;
480 }
481
482 int strheight(const char *p)
483 {
484         int i = 1, incr;
485         const char *s, *s1, *s2;
486
487         for (s = p; ; s += incr) {
488                 s1 = strchr(s, '\n');
489                 s2 = strstr(s, "\\n");
490                 if (s2 == NULL)
491                         s = s1;
492                 else if (s1 == NULL)
493                         s = s2;
494                 else
495                         s = MIN(s1, s2);
496                 if (s == NULL)
497                         break;
498                 incr = 1 + (s == s2);
499                 i++;
500         }
501         return i;
502 }
503
504 void print_arrows(WINDOW *dialog, int scroll, int menu_height, int item_no,
505                   int box_x, int box_y, int tag_x, int cur_x, int cur_y)
506 {
507     wmove(dialog, box_y, box_x + tag_x + 1);
508     wattrset(dialog, scroll ? uarrow_attr : menubox_attr);
509     waddch(dialog, scroll ? ACS_UARROW : ACS_HLINE);
510     wmove(dialog, box_y, box_x + tag_x + 2);
511     waddch(dialog, scroll ? '(' : ACS_HLINE);
512     wmove(dialog, box_y, box_x + tag_x + 3);
513     waddch(dialog, scroll ? '-' : ACS_HLINE);
514     wmove(dialog, box_y, box_x + tag_x + 4);
515     waddch(dialog, scroll ? ')' : ACS_HLINE);
516     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 1);
517     wattrset(dialog, scroll+menu_height < item_no ? darrow_attr : menubox_border_attr);
518     waddch(dialog, scroll+menu_height < item_no ? ACS_DARROW : ACS_HLINE);
519     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 2);
520     waddch(dialog, scroll+menu_height < item_no ? '(' : ACS_HLINE);
521     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 3);
522     waddch(dialog, scroll+menu_height < item_no ? '+' : ACS_HLINE);
523     wmove(dialog, box_y + menu_height + 1, box_x + tag_x + 4);
524     waddch(dialog, scroll+menu_height < item_no ? ')' : ACS_HLINE);
525     wmove(dialog, cur_y, cur_x);  /* Restore cursor position */
526 }
527