blob: bc41d44de930fb8d91939a8bedc29f7bb0205ef4 [file] [log] [blame]
micky3879b9f5e72025-07-08 18:04:53 -04001/****************************************************************************
2 * Copyright 2018-2021,2022 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.27 2022/12/04 00:40:11 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
48static bool
49valid_cap(NCURSES_CONST char *name)
50{
51 char *value = tigetstr(name);
52 return (value != 0 && value != (char *) -1) ? TRUE : FALSE;
53}
54
55static attr_t
56next_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
89static void
90our_content(int pair, int *fg, int *bg)
91{
92 pair %= COLOR_PAIRS;
93 *fg = (pair / COLORS) % COLORS;
94 *bg = (pair % COLORS);
95}
96
97static int
98make_color(int now)
99{
100 int fg, bg;
101 our_content(now, &fg, &bg);
102 return alloc_pair(fg, bg);
103}
104
105static int
106next_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
123static time_t
124now(void)
125{
126 return time((time_t *) 0);
127}
128
129static void
130usage(int ok)
131{
132 static const char *msg[] =
133 {
134 "Usage: demo_new_pair [options]"
135 ,""
136 ,"Repeatedly print using all possible color combinations."
137 ,""
138 ,USAGE_COMMON
139 ,"Options:"
140 ," -g use getcchar to check setcchar"
141 ," -i use init_pair rather than alloc_pair"
142 ," -p start in paged-mode"
143 ," -s start in single-step mode"
144 ," -w print a wide-character cell"
145 };
146 unsigned n;
147 for (n = 0; n < SIZEOF(msg); ++n) {
148 fprintf(stderr, "%s\n", msg[n]);
149 }
150 ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
151}
152
153#define use_pages() \
154 paged_mode = TRUE, single_mode = TRUE
155
156#define use_single() \
157 paged_mode = FALSE, single_mode = TRUE
158
159#define update_modes() \
160 scrollok(stdscr, !paged_mode); \
161 nodelay(stdscr, !single_mode || paged_mode)
162/* *INDENT-OFF* */
163VERSION_COMMON()
164/* *INDENT-ON* */
165
166int
167main(int argc, char *argv[])
168{
169 static const char *help[] =
170 {
171 "This program iterates over the possible color combinations,",
172 "allocating or initializing color pairs. For best results,",
173 "choose screen-width dividing evenly into the number of colors,",
174 "e.g.,",
175 "",
176 " 32x64,32x128 256 colors",
177 " 24x44,24x88 88 colors",
178 " 32x64,24x128 16 colors",
179 "",
180 "Keys:",
181 " c toggle between coloring and de-coloring cells",
182 " p show one page at a time",
183 " s show one character at a time",
184 " <space> display char/page without pausing",
185 " v/V cycle through video attributes",
186 " w toggle between \"#\" and a double-width equivalent",
187 " ? print this screen (exit on any character).",
188 "",
189 "To exit this program, press ^Q, ^[ or \"q\".",
190 0
191 };
192
193 bool done = FALSE;
194 bool check_set = FALSE;
195 bool clobber = FALSE;
196 bool hascolor = FALSE;
197 bool use_init = FALSE;
198 bool use_wide = FALSE;
199 bool paged_mode = FALSE;
200 bool single_mode = FALSE;
201 int video_mode = 0;
202 int current;
203 int ch;
204 wchar_t wch[2];
205 time_t start = now();
206 long total_cells = 0;
207 FILE *output = 0;
208
209 setlocale(LC_ALL, "");
210
211 while ((ch = getopt(argc, argv, OPTS_COMMON "gipsw")) != -1) {
212 switch (ch) {
213 case 'g':
214 check_set = TRUE;
215 break;
216 case 'i':
217 use_init = TRUE;
218 break;
219 case 'p':
220 use_pages();
221 break;
222 case 's':
223 use_single();
224 break;
225 case 'w':
226 use_wide = TRUE;
227 break;
228 case OPTS_VERSION:
229 show_version(argv);
230 ExitProgram(EXIT_SUCCESS);
231 default:
232 usage(ch == OPTS_USAGE);
233 /* NOTREACHED */
234 }
235 }
236
237 if (isatty(fileno(stderr))) {
238 output = stderr;
239 } else if ((ch = open("/dev/tty", O_WRONLY)) >= 0) {
240 output = fdopen(ch, "w");
241 } else {
242 fprintf(stderr, "cannot open terminal for output\n");
243 ExitProgram(EXIT_FAILURE);
244 }
245 if (newterm(NULL, output, stdin) == 0) {
246 fprintf(stderr, "Cannot initialize terminal\n");
247 fclose(output);
248 ExitProgram(EXIT_FAILURE);
249 }
250 (void) cbreak(); /* read chars without wait for \n */
251 (void) noecho(); /* don't echo input */
252 update_modes();
253 curs_set(0);
254
255 keypad(stdscr, TRUE);
256
257 if ((hascolor = has_colors())) {
258 start_color();
259 current = 1;
260 } else {
261 current = 0;
262 }
263
264 /*
265 * Repeatedly cycle through all colors, initializing pairs as needed.
266 * Provide for single-stepping, or page-at-a-time, as well as quitting.
267 */
268 while (!done) {
269 cchar_t temp;
270 attr_t my_attrs;
271 int my_pair;
272
273 switch (getch()) {
274 case HELP_KEY_1:
275 popup_msg(stdscr, help);
276 break;
277 case 'p':
278 /* step-by-page */
279 use_pages();
280 update_modes();
281 break;
282 case 's':
283 /* step-by-char */
284 use_single();
285 update_modes();
286 break;
287 case ' ':
288 single_mode = FALSE;
289 update_modes();
290 break;
291 case QUIT:
292 case ESCAPE:
293 case 'q':
294 done = TRUE;
295 continue;
296 case 'c':
297 clobber = !clobber;
298 continue;
299 case 'v':
300 if (--video_mode < 0)
301 video_mode = MAX_ATTR;
302 continue;
303 case 'V':
304 if (video_mode > MAX_ATTR)
305 video_mode = 0;
306 continue;
307 case 'w':
308 use_wide = !use_wide;
309 continue;
310 case ERR:
311 break;
312 default:
313 beep();
314 break;
315 }
316 if (hascolor) {
317 my_attrs = next_attr(video_mode);
318 if (clobber) {
319 int fg, bg;
320 our_content(current, &fg, &bg);
321 my_pair = find_pair(fg, bg);
322 if (my_pair > 0) {
323 free_pair(my_pair);
324 }
325 my_pair = 0;
326 } else {
327 my_pair = (use_init
328 ? next_color(current)
329 : make_color(current));
330 }
331 } else {
332 my_attrs = next_attr(current);
333 my_pair = 0;
334 }
335 if (my_pair < 0)
336 break;
337 wch[0] = use_wide ? 0xff03 : '#';
338 wch[1] = 0;
339 setcchar(&temp, wch, my_attrs,
340 (short) my_pair,
341 (use_init ? NULL : (void *) &my_pair));
342
343 if (check_set) {
344 int problem = 0;
345 wchar_t chk_wch[2];
346 attr_t chk_attrs = 0;
347 short chk_pair = 0;
348 int chk_pair2 = 0;
349
350#define AllButColor(a) ((a) & (A_ATTRIBUTES & ~A_COLOR))
351
352 if (getcchar(&temp, NULL, &chk_attrs, &chk_pair,
353 (use_init ? NULL : (void *) &chk_pair2)) != 2) {
354 problem = 1;
355 } else if (getcchar(&temp, chk_wch, &chk_attrs, &chk_pair,
356 (use_init ? NULL : (void *) &chk_pair2)) != OK) {
357 problem = 2;
358 } else if (chk_wch[0] != wch[0]) {
359 problem = 3;
360 } else if (AllButColor(my_attrs) != AllButColor(chk_attrs)) {
361 problem = 4;
362 } else if (my_pair != chk_pair) {
363 problem = 4;
364 } else if (!use_init && (my_pair != chk_pair2)) {
365 problem = 5;
366 }
367 if (problem) {
368 wch[0] = (wchar_t) (problem + '0');
369 setcchar(&temp, wch, my_attrs,
370 (short) my_pair,
371 (use_init ? NULL : (void *) &my_pair));
372 }
373 }
374
375 /*
376 * At the end of a page, move the cursor to the home position.
377 */
378 if ((add_wch(&temp) == ERR) && paged_mode) {
379 nodelay(stdscr, !single_mode);
380 move(0, 0);
381 }
382 total_cells += 1 + (use_wide ? 1 : 0);
383 ++current;
384 }
385 stop_curses();
386 fclose(output);
387
388 printf("%.1f cells/second\n",
389 (double) (total_cells) / (double) (now() - start));
390
391 ExitProgram(EXIT_SUCCESS);
392}
393
394#else
395int
396main(void)
397{
398 printf("This program requires the ncurses alloc_pair function\n");
399 ExitProgram(EXIT_FAILURE);
400}
401#endif