ncurses 6.1 - patch 20180303
[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.18 2017/10/11 22:16:14 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++] = WA_NORMAL;
67         if (valid_cap("smso"))
68             bits[limit++] = WA_STANDOUT;
69         if (valid_cap("smul"))
70             bits[limit++] = WA_UNDERLINE;
71         if (valid_cap("rev"))
72             bits[limit++] = WA_REVERSE;
73         if (valid_cap("blink"))
74             bits[limit++] = WA_BLINK;
75         if (valid_cap("dim"))
76             bits[limit++] = WA_DIM;
77         if (valid_cap("bold"))
78             bits[limit++] = WA_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         fprintf(stderr, "Cannot initialize terminal\n");
234         fclose(output);
235         ExitProgram(EXIT_FAILURE);
236     }
237     (void) cbreak();            /* read chars without wait for \n */
238     (void) noecho();            /* don't echo input */
239     update_modes();
240     curs_set(0);
241
242     keypad(stdscr, TRUE);
243
244     if ((hascolor = has_colors())) {
245         start_color();
246         current = 1;
247     } else {
248         current = 0;
249     }
250
251     /*
252      * Repeatedly cycle through all colors, initializing pairs as needed.
253      * Provide for single-stepping, or page-at-a-time, as well as quitting.
254      */
255     while (!done) {
256         cchar_t temp;
257         attr_t my_attrs;
258         int my_pair;
259
260         switch (getch()) {
261         case HELP_KEY_1:
262             popup_msg(stdscr, help);
263             break;
264         case 'p':
265             /* step-by-page */
266             use_pages();
267             update_modes();
268             break;
269         case 's':
270             /* step-by-char */
271             use_single();
272             update_modes();
273             break;
274         case ' ':
275             single_mode = FALSE;
276             update_modes();
277             break;
278         case QUIT:
279         case ESCAPE:
280         case 'q':
281             done = TRUE;
282             continue;
283         case 'c':
284             clobber = !clobber;
285             continue;
286         case 'v':
287             if (--video_mode < 0)
288                 video_mode = MAX_ATTR;
289             continue;
290         case 'V':
291             if (video_mode > MAX_ATTR)
292                 video_mode = 0;
293             continue;
294         case 'w':
295             use_wide = !use_wide;
296             continue;
297         case ERR:
298             break;
299         default:
300             beep();
301             break;
302         }
303         if (hascolor) {
304             my_attrs = next_attr(video_mode);
305             if (clobber) {
306                 int fg, bg;
307                 our_content(current, &fg, &bg);
308                 my_pair = find_pair(fg, bg);
309                 if (my_pair > 0) {
310                     free_pair(my_pair);
311                 }
312                 my_pair = 0;
313             } else {
314                 my_pair = (use_init
315                            ? next_color(current)
316                            : make_color(current));
317             }
318         } else {
319             my_attrs = next_attr(current);
320             my_pair = 0;
321         }
322         if (my_pair < 0)
323             break;
324         wch[0] = use_wide ? 0xff03 : '#';
325         wch[1] = 0;
326         setcchar(&temp, wch, my_attrs,
327                  (short) my_pair,
328                  (use_init ? NULL : (void *) &my_pair));
329         /*
330          * At the end of a page, move the cursor to the home position.
331          */
332         if ((add_wch(&temp) == ERR) && paged_mode) {
333             nodelay(stdscr, !single_mode);
334             move(0, 0);
335         }
336         total_cells += 1 + (use_wide ? 1 : 0);
337         ++current;
338     }
339     exit_curses();
340     fclose(output);
341
342     printf("%.1f cells/second\n",
343            (double) (total_cells) / (double) (now() - start));
344
345     ExitProgram(EXIT_SUCCESS);
346 }
347
348 #else
349 int
350 main(void)
351 {
352     printf("This program requires the ncurses alloc_pair function\n");
353     ExitProgram(EXIT_FAILURE);
354 }
355 #endif