a0d069c06011cd6349d934e7c2796bc507a6c072
[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.11 2017/04/08 21:48:53 tom Exp $
30  *
31  * Demonstrate the alloc_pair() function.
32  */
33
34 #include <test.priv.h>
35 #include <time.h>
36
37 #if HAVE_ALLOC_PAIR && USE_WIDEC_SUPPORT
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42
43 #define MAX_BITS 8              /* all but A_ALTCHARSET */
44 #define MAX_ATTR ((1<<MAX_BITS)-1)
45
46 static bool
47 valid_cap(NCURSES_CONST char *name)
48 {
49     char *value = tigetstr(name);
50     return (value != 0 && value != (char *) -1) ? TRUE : FALSE;
51 }
52
53 static attr_t
54 next_attr(int now)
55 {
56     static bool init = FALSE;
57     static attr_t table[MAX_BITS * MAX_BITS];
58     static int limit = 0;
59
60     if (!init) {
61         int j, k;
62         attr_t bits[MAX_BITS];
63
64         init = TRUE;
65         bits[limit++] = A_NORMAL;
66         if (valid_cap("smso"))
67             bits[limit++] = A_STANDOUT;
68         if (valid_cap("smul"))
69             bits[limit++] = A_UNDERLINE;
70         if (valid_cap("rev"))
71             bits[limit++] = A_REVERSE;
72         if (valid_cap("blink"))
73             bits[limit++] = A_BLINK;
74         if (valid_cap("dim"))
75             bits[limit++] = A_DIM;
76         if (valid_cap("bold"))
77             bits[limit++] = A_BOLD;
78         for (j = 0; j < limit; ++j) {
79             for (k = 0; k < limit; ++k) {
80                 table[j * limit + k] = bits[j] | bits[k];
81             }
82         }
83     }
84     return table[now % limit];
85 }
86
87 static void
88 our_content(int pair, int *fg, int *bg)
89 {
90     pair %= COLOR_PAIRS;
91     *fg = (pair / COLORS) % COLORS;
92     *bg = (pair % COLORS);
93 }
94
95 static int
96 make_color(int now)
97 {
98     int fg, bg;
99     our_content(now, &fg, &bg);
100     return alloc_pair(fg, bg);
101 }
102
103 static int
104 next_color(int now)
105 {
106     int result = 0;
107     if ((short) now > 0) {
108         if (now < COLOR_PAIRS) {
109             int fg, bg;
110             our_content(now, &fg, &bg);
111             if (init_pair((short) now, (short) fg, (short) bg) != OK)
112                 now = ERR;
113         } else {
114             now %= COLOR_PAIRS;
115         }
116         result = now;
117     }
118     return result;
119 }
120
121 static void
122 show_help(const char **help)
123 {
124     WINDOW *mywin = newwin(LINES, COLS, 0, 0);
125     int n;
126
127     wmove(mywin, 1, 1);
128     for (n = 0; help[n] != 0; ++n) {
129         wmove(mywin, 1 + n, 2);
130         wprintw(mywin, "%.*s\n", COLS - 4, help[n]);
131     }
132     box(mywin, 0, 0);
133     wgetch(mywin);
134     delwin(mywin);
135     touchwin(stdscr);
136     refresh();
137 }
138
139 static time_t
140 now(void)
141 {
142     return time((time_t *) 0);
143 }
144
145 static void
146 usage(void)
147 {
148     static const char *msg[] =
149     {
150         "Usage: demo_new_pair [options]",
151         "",
152         "Repeatedly print using all possible color combinations.",
153         "",
154         "Options:",
155         " -i       use init_pair rather than alloc_pair",
156         " -p       start in paged-mode",
157         " -s       start in single-step mode",
158         " -w       print a wide-character cell",
159     };
160     unsigned n;
161     for (n = 0; n < SIZEOF(msg); ++n) {
162         fprintf(stderr, "%s\n", msg[n]);
163     }
164     ExitProgram(EXIT_FAILURE);
165 }
166
167 #define use_pages() \
168         paged_mode = TRUE, single_mode = TRUE
169
170 #define use_single() \
171         paged_mode = FALSE, single_mode = TRUE
172
173 #define update_modes() \
174             scrollok(stdscr, !paged_mode); \
175             nodelay(stdscr, !single_mode || paged_mode)
176
177 int
178 main(int argc, char *argv[])
179 {
180     static const char *help[] =
181     {
182         "This program iterates over the possible color combinations,",
183         "allocating or initializing color pairs.  For best results,",
184         "choose screen-width dividing evenly into the number of colors,",
185         "e.g.,",
186         "",
187         "  32x64,32x128  256 colors",
188         "  24x44,24x88   88 colors",
189         "  32x64,24x128  16 colors",
190         "",
191         "Keys:",
192         "  c      toggle between coloring and de-coloring cells",
193         "  p      show one page at a time",
194         "  s      show one character at a time",
195         " <space> display char/page without pausing",
196         "  v/V    cycle through video attributes",
197         "  w      toggle between \"#\" and a double-width equivalent",
198         "  ?      print this screen (exit on any character).",
199         "",
200         "To exit this program, press ^Q, ^[ or \"q\".",
201         0
202     };
203
204     bool done = FALSE;
205     bool clobber = FALSE;
206     bool hascolor = FALSE;
207     bool use_init = FALSE;
208     bool use_wide = FALSE;
209     bool paged_mode = FALSE;
210     bool single_mode = FALSE;
211     int video_mode = 0;
212     int current;
213     int ch;
214     wchar_t wch[2];
215     time_t start = now();
216     long total_cells = 0;
217     FILE *output = 0;
218
219     setlocale(LC_ALL, "");
220
221     while ((ch = getopt(argc, argv, "ipsw")) != -1) {
222         switch (ch) {
223         case 'i':
224             use_init = TRUE;
225             break;
226         case 'p':
227             use_pages();
228             break;
229         case 's':
230             use_single();
231             break;
232         case 'w':
233             use_wide = TRUE;
234             break;
235         default:
236             usage();
237             break;
238         }
239     }
240
241     if (isatty(fileno(stderr))) {
242         output = stderr;
243     } else if ((ch = open("/dev/tty", O_WRONLY)) != 0) {
244         output = fdopen(ch, "w");
245     } else {
246         fprintf(stderr, "cannot open terminal for output\n");
247         ExitProgram(EXIT_FAILURE);
248     }
249     if (newterm(NULL, output, stdin) == 0)
250         usage();
251     (void) cbreak();            /* read chars without wait for \n */
252     (void) noecho();            /* don't echo input */
253     update_modes();
254     curs_set(0);
255
256     keypad(stdscr, TRUE);
257
258     if ((hascolor = has_colors())) {
259         start_color();
260         current = 1;
261     } else {
262         current = 0;
263     }
264
265     /*
266      * Repeatedly cycle through all colors, initializing pairs as needed.
267      * Provide for single-stepping, or page-at-a-time, as well as quitting.
268      */
269     while (!done) {
270         cchar_t temp;
271         attr_t my_attrs;
272         int my_pair;
273
274         switch (getch()) {
275         case '?':
276             show_help(help);
277             break;
278         case 'p':
279             /* step-by-page */
280             use_pages();
281             update_modes();
282             break;
283         case 's':
284             /* step-by-char */
285             use_single();
286             update_modes();
287             break;
288         case ' ':
289             single_mode = FALSE;
290             update_modes();
291             break;
292         case QUIT:
293         case ESCAPE:
294         case 'q':
295             done = TRUE;
296             continue;
297         case 'c':
298             clobber = !clobber;
299             continue;
300         case 'v':
301             if (--video_mode < 0)
302                 video_mode = MAX_ATTR;
303             continue;
304         case 'V':
305             if (video_mode > MAX_ATTR)
306                 video_mode = 0;
307             continue;
308         case 'w':
309             use_wide = !use_wide;
310             continue;
311         case ERR:
312             break;
313         default:
314             beep();
315             break;
316         }
317         if (hascolor) {
318             my_attrs = next_attr(video_mode);
319             if (clobber) {
320                 int fg, bg;
321                 our_content(current, &fg, &bg);
322                 my_pair = find_pair(fg, bg);
323                 if (my_pair > 0) {
324                     free_pair(my_pair);
325                 }
326                 my_pair = 0;
327             } else {
328                 my_pair = (use_init
329                            ? next_color(current)
330                            : make_color(current));
331             }
332         } else {
333             my_attrs = next_attr(current);
334             my_pair = 0;
335         }
336         if (my_pair < 0)
337             break;
338         wch[0] = use_wide ? 0xff03 : '#';
339         wch[1] = 0;
340         setcchar(&temp, wch, my_attrs, (short) my_pair, NULL);
341         /*
342          * At the end of a page, move the cursor to the home position.
343          */
344         if ((add_wch(&temp) == ERR) && paged_mode) {
345             nodelay(stdscr, !single_mode);
346             move(0, 0);
347         }
348         total_cells += 1 + (use_wide ? 1 : 0);
349         ++current;
350     }
351     endwin();
352
353     printf("%.1f cells/second\n",
354            (double) (total_cells) / (double) (now() - start));
355
356     ExitProgram(EXIT_SUCCESS);
357 }
358
359 #else
360 int
361 main(void)
362 {
363     printf("This program requires the ncurses alloc_pair function\n");
364     ExitProgram(EXIT_FAILURE);
365 }
366 #endif