ncurses 6.0 - patch 20170311
[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.10 2017/03/10 09:47:15 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 #define MAX_BITS 8              /* all but A_ALTCHARSET */
40 #define MAX_ATTR ((1<<MAX_BITS)-1)
41
42 static bool
43 valid_cap(NCURSES_CONST char *name)
44 {
45     char *value = tigetstr(name);
46     return (value != 0 && value != (char *) -1) ? TRUE : FALSE;
47 }
48
49 static attr_t
50 next_attr(int now)
51 {
52     static bool init = FALSE;
53     static attr_t table[MAX_BITS * MAX_BITS];
54     static int limit = 0;
55
56     if (!init) {
57         int j, k;
58         attr_t bits[MAX_BITS];
59
60         init = TRUE;
61         bits[limit++] = A_NORMAL;
62         if (valid_cap("smso"))
63             bits[limit++] = A_STANDOUT;
64         if (valid_cap("smul"))
65             bits[limit++] = A_UNDERLINE;
66         if (valid_cap("rev"))
67             bits[limit++] = A_REVERSE;
68         if (valid_cap("blink"))
69             bits[limit++] = A_BLINK;
70         if (valid_cap("dim"))
71             bits[limit++] = A_DIM;
72         if (valid_cap("bold"))
73             bits[limit++] = A_BOLD;
74         for (j = 0; j < limit; ++j) {
75             for (k = 0; k < limit; ++k) {
76                 table[j * limit + k] = bits[j] | bits[k];
77             }
78         }
79     }
80     return table[now % limit];
81 }
82
83 static void
84 our_content(int pair, int *fg, int *bg)
85 {
86     pair %= COLOR_PAIRS;
87     *fg = (pair / COLORS) % COLORS;
88     *bg = (pair % COLORS);
89 }
90
91 static int
92 make_color(int now)
93 {
94     int fg, bg;
95     our_content(now, &fg, &bg);
96     return alloc_pair(fg, bg);
97 }
98
99 static int
100 next_color(int now)
101 {
102     int result = 0;
103     if ((short) now > 0) {
104         if (now < COLOR_PAIRS) {
105             int fg, bg;
106             our_content(now, &fg, &bg);
107             if (init_pair((short) now, (short) fg, (short) bg) != OK)
108                 now = ERR;
109         } else {
110             now %= COLOR_PAIRS;
111         }
112         result = now;
113     }
114     return result;
115 }
116
117 static void
118 show_help(const char **help)
119 {
120     WINDOW *mywin = newwin(LINES, COLS, 0, 0);
121     int n;
122
123     wmove(mywin, 1, 1);
124     for (n = 0; help[n] != 0; ++n) {
125         wmove(mywin, 1 + n, 2);
126         wprintw(mywin, "%.*s\n", COLS - 4, help[n]);
127     }
128     box(mywin, 0, 0);
129     wgetch(mywin);
130     delwin(mywin);
131     touchwin(stdscr);
132     refresh();
133 }
134
135 static time_t
136 now(void)
137 {
138     return time((time_t *) 0);
139 }
140
141 static void
142 usage(void)
143 {
144     static const char *msg[] =
145     {
146         "Usage: demo_new_pair [options]",
147         "",
148         "Repeatedly print using all possible color combinations.",
149         "",
150         "Options:",
151         " -i       use init_pair rather than alloc_pair",
152         " -p       start in paged-mode",
153         " -s       start in single-step mode",
154         " -w       print a wide-character cell",
155     };
156     unsigned n;
157     for (n = 0; n < SIZEOF(msg); ++n) {
158         fprintf(stderr, "%s\n", msg[n]);
159     }
160     ExitProgram(EXIT_FAILURE);
161 }
162
163 #define use_pages() \
164         paged_mode = TRUE, single_mode = TRUE
165
166 #define use_single() \
167         paged_mode = FALSE, single_mode = TRUE
168
169 #define update_modes() \
170             scrollok(stdscr, !paged_mode); \
171             nodelay(stdscr, !single_mode || paged_mode)
172
173 int
174 main(int argc, char *argv[])
175 {
176     static const char *help[] =
177     {
178         "This program iterates over the possible color combinations,",
179         "allocating or initializing color pairs.  For best results,",
180         "choose screen-width dividing evenly into the number of colors,",
181         "e.g.,",
182         "",
183         "  32x64,32x128  256 colors",
184         "  24x44,24x88   88 colors",
185         "  32x64,24x128  16 colors",
186         "",
187         "Keys:",
188         "  c      toggle between coloring and de-coloring cells",
189         "  p      show one page at a time",
190         "  s      show one character at a time",
191         " <space> display char/page without pausing",
192         "  v/V    cycle through video attributes",
193         "  w      toggle between \"#\" and a double-width equivalent",
194         "  ?      print this screen (exit on any character).",
195         "",
196         "To exit this program, press ^Q, ^[ or \"q\".",
197         0
198     };
199
200     bool done = FALSE;
201     bool clobber = FALSE;
202     bool hascolor = FALSE;
203     bool use_init = FALSE;
204     bool use_wide = FALSE;
205     bool paged_mode = FALSE;
206     bool single_mode = FALSE;
207     int video_mode = 0;
208     int current;
209     int ch;
210     wchar_t wch[2];
211     time_t start = now();
212     long total_cells = 0;
213
214     setlocale(LC_ALL, "");
215
216     while ((ch = getopt(argc, argv, "ipsw")) != -1) {
217         switch (ch) {
218         case 'i':
219             use_init = TRUE;
220             break;
221         case 'p':
222             use_pages();
223             break;
224         case 's':
225             use_single();
226             break;
227         case 'w':
228             use_wide = TRUE;
229             break;
230         default:
231             usage();
232             break;
233         }
234     }
235
236     if (newterm(NULL, stderr, stdin) == 0)
237         usage();
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 '?':
263             show_help(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, (short) my_pair, NULL);
328         /*
329          * At the end of a page, move the cursor to the home position.
330          */
331         if ((add_wch(&temp) == ERR) && paged_mode) {
332             nodelay(stdscr, !single_mode);
333             move(0, 0);
334         }
335         total_cells += 1 + (use_wide ? 1 : 0);
336         ++current;
337     }
338     endwin();
339
340     printf("%.1f cells/second\n",
341            (double) (total_cells) / (double) (now() - start));
342
343     ExitProgram(EXIT_SUCCESS);
344 }
345
346 #else
347 int
348 main(void)
349 {
350     printf("This program requires the ncurses alloc_pair function\n");
351     ExitProgram(EXIT_FAILURE);
352 }
353 #endif