ncurses 6.0 - patch 20170513
[ncurses.git] / test / demo_new_pair.c
1 /****************************************************************************
2  * Copyright (c) 2017 Free Software Foundation, Inc.                        *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28 /*
29  * $Id: demo_new_pair.c,v 1.13 2017/04/15 17:36:00 tom Exp $
30  *
31  * Demonstrate the alloc_pair() function.
32  */
33
34 #include <test.priv.h>
35 #include <time.h>
36 #include <popup_msg.h>
37
38 #if HAVE_ALLOC_PAIR && USE_WIDEC_SUPPORT
39
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43
44 #define MAX_BITS 8              /* all but A_ALTCHARSET */
45 #define MAX_ATTR ((1<<MAX_BITS)-1)
46
47 static bool
48 valid_cap(NCURSES_CONST char *name)
49 {
50     char *value = tigetstr(name);
51     return (value != 0 && value != (char *) -1) ? TRUE : FALSE;
52 }
53
54 static attr_t
55 next_attr(int now)
56 {
57     static bool init = FALSE;
58     static attr_t table[MAX_BITS * MAX_BITS];
59     static int limit = 0;
60
61     if (!init) {
62         int j, k;
63         attr_t bits[MAX_BITS];
64
65         init = TRUE;
66         bits[limit++] = A_NORMAL;
67         if (valid_cap("smso"))
68             bits[limit++] = A_STANDOUT;
69         if (valid_cap("smul"))
70             bits[limit++] = A_UNDERLINE;
71         if (valid_cap("rev"))
72             bits[limit++] = A_REVERSE;
73         if (valid_cap("blink"))
74             bits[limit++] = A_BLINK;
75         if (valid_cap("dim"))
76             bits[limit++] = A_DIM;
77         if (valid_cap("bold"))
78             bits[limit++] = A_BOLD;
79         for (j = 0; j < limit; ++j) {
80             for (k = 0; k < limit; ++k) {
81                 table[j * limit + k] = bits[j] | bits[k];
82             }
83         }
84     }
85     return table[now % limit];
86 }
87
88 static void
89 our_content(int pair, int *fg, int *bg)
90 {
91     pair %= COLOR_PAIRS;
92     *fg = (pair / COLORS) % COLORS;
93     *bg = (pair % COLORS);
94 }
95
96 static int
97 make_color(int now)
98 {
99     int fg, bg;
100     our_content(now, &fg, &bg);
101     return alloc_pair(fg, bg);
102 }
103
104 static int
105 next_color(int now)
106 {
107     int result = 0;
108     if ((short) now > 0) {
109         if (now < COLOR_PAIRS) {
110             int fg, bg;
111             our_content(now, &fg, &bg);
112             if (init_pair((short) now, (short) fg, (short) bg) != OK)
113                 now = ERR;
114         } else {
115             now %= COLOR_PAIRS;
116         }
117         result = now;
118     }
119     return result;
120 }
121
122 static time_t
123 now(void)
124 {
125     return time((time_t *) 0);
126 }
127
128 static void
129 usage(void)
130 {
131     static const char *msg[] =
132     {
133         "Usage: demo_new_pair [options]",
134         "",
135         "Repeatedly print using all possible color combinations.",
136         "",
137         "Options:",
138         " -i       use init_pair rather than alloc_pair",
139         " -p       start in paged-mode",
140         " -s       start in single-step mode",
141         " -w       print a wide-character cell",
142     };
143     unsigned n;
144     for (n = 0; n < SIZEOF(msg); ++n) {
145         fprintf(stderr, "%s\n", msg[n]);
146     }
147     ExitProgram(EXIT_FAILURE);
148 }
149
150 #define use_pages() \
151         paged_mode = TRUE, single_mode = TRUE
152
153 #define use_single() \
154         paged_mode = FALSE, single_mode = TRUE
155
156 #define update_modes() \
157             scrollok(stdscr, !paged_mode); \
158             nodelay(stdscr, !single_mode || paged_mode)
159
160 int
161 main(int argc, char *argv[])
162 {
163     static const char *help[] =
164     {
165         "This program iterates over the possible color combinations,",
166         "allocating or initializing color pairs.  For best results,",
167         "choose screen-width dividing evenly into the number of colors,",
168         "e.g.,",
169         "",
170         "  32x64,32x128  256 colors",
171         "  24x44,24x88   88 colors",
172         "  32x64,24x128  16 colors",
173         "",
174         "Keys:",
175         "  c      toggle between coloring and de-coloring cells",
176         "  p      show one page at a time",
177         "  s      show one character at a time",
178         " <space> display char/page without pausing",
179         "  v/V    cycle through video attributes",
180         "  w      toggle between \"#\" and a double-width equivalent",
181         "  ?      print this screen (exit on any character).",
182         "",
183         "To exit this program, press ^Q, ^[ or \"q\".",
184         0
185     };
186
187     bool done = FALSE;
188     bool clobber = FALSE;
189     bool hascolor = FALSE;
190     bool use_init = FALSE;
191     bool use_wide = FALSE;
192     bool paged_mode = FALSE;
193     bool single_mode = FALSE;
194     int video_mode = 0;
195     int current;
196     int ch;
197     wchar_t wch[2];
198     time_t start = now();
199     long total_cells = 0;
200     FILE *output = 0;
201
202     setlocale(LC_ALL, "");
203
204     while ((ch = getopt(argc, argv, "ipsw")) != -1) {
205         switch (ch) {
206         case 'i':
207             use_init = TRUE;
208             break;
209         case 'p':
210             use_pages();
211             break;
212         case 's':
213             use_single();
214             break;
215         case 'w':
216             use_wide = TRUE;
217             break;
218         default:
219             usage();
220             break;
221         }
222     }
223
224     if (isatty(fileno(stderr))) {
225         output = stderr;
226     } else if ((ch = open("/dev/tty", O_WRONLY)) != 0) {
227         output = fdopen(ch, "w");
228     } else {
229         fprintf(stderr, "cannot open terminal for output\n");
230         ExitProgram(EXIT_FAILURE);
231     }
232     if (newterm(NULL, output, stdin) == 0)
233         usage();
234     (void) cbreak();            /* read chars without wait for \n */
235     (void) noecho();            /* don't echo input */
236     update_modes();
237     curs_set(0);
238
239     keypad(stdscr, TRUE);
240
241     if ((hascolor = has_colors())) {
242         start_color();
243         current = 1;
244     } else {
245         current = 0;
246     }
247
248     /*
249      * Repeatedly cycle through all colors, initializing pairs as needed.
250      * Provide for single-stepping, or page-at-a-time, as well as quitting.
251      */
252     while (!done) {
253         cchar_t temp;
254         attr_t my_attrs;
255         int my_pair;
256
257         switch (getch()) {
258         case HELP_KEY_1:
259             popup_msg(stdscr, help);
260             break;
261         case 'p':
262             /* step-by-page */
263             use_pages();
264             update_modes();
265             break;
266         case 's':
267             /* step-by-char */
268             use_single();
269             update_modes();
270             break;
271         case ' ':
272             single_mode = FALSE;
273             update_modes();
274             break;
275         case QUIT:
276         case ESCAPE:
277         case 'q':
278             done = TRUE;
279             continue;
280         case 'c':
281             clobber = !clobber;
282             continue;
283         case 'v':
284             if (--video_mode < 0)
285                 video_mode = MAX_ATTR;
286             continue;
287         case 'V':
288             if (video_mode > MAX_ATTR)
289                 video_mode = 0;
290             continue;
291         case 'w':
292             use_wide = !use_wide;
293             continue;
294         case ERR:
295             break;
296         default:
297             beep();
298             break;
299         }
300         if (hascolor) {
301             my_attrs = next_attr(video_mode);
302             if (clobber) {
303                 int fg, bg;
304                 our_content(current, &fg, &bg);
305                 my_pair = find_pair(fg, bg);
306                 if (my_pair > 0) {
307                     free_pair(my_pair);
308                 }
309                 my_pair = 0;
310             } else {
311                 my_pair = (use_init
312                            ? next_color(current)
313                            : make_color(current));
314             }
315         } else {
316             my_attrs = next_attr(current);
317             my_pair = 0;
318         }
319         if (my_pair < 0)
320             break;
321         wch[0] = use_wide ? 0xff03 : '#';
322         wch[1] = 0;
323         setcchar(&temp, wch, my_attrs, (short) my_pair, NULL);
324         /*
325          * At the end of a page, move the cursor to the home position.
326          */
327         if ((add_wch(&temp) == ERR) && paged_mode) {
328             nodelay(stdscr, !single_mode);
329             move(0, 0);
330         }
331         total_cells += 1 + (use_wide ? 1 : 0);
332         ++current;
333     }
334     endwin();
335     fclose(output);
336
337     printf("%.1f cells/second\n",
338            (double) (total_cells) / (double) (now() - start));
339
340     ExitProgram(EXIT_SUCCESS);
341 }
342
343 #else
344 int
345 main(void)
346 {
347     printf("This program requires the ncurses alloc_pair function\n");
348     ExitProgram(EXIT_FAILURE);
349 }
350 #endif