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