ncurses/test/demo_new_pair.c

357 lines
8.7 KiB
C

/****************************************************************************
* Copyright 2018-2019,2020 Thomas E. Dickey *
* Copyright 2017 Free Software Foundation, Inc. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, distribute with modifications, sublicense, and/or sell *
* copies of the Software, and to permit persons to whom the Software is *
* furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included *
* in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
* *
* Except as contained in this notice, the name(s) of the above copyright *
* holders shall not be used in advertising or otherwise to promote the *
* sale, use or other dealings in this Software without prior written *
* authorization. *
****************************************************************************/
/*
* $Id: demo_new_pair.c,v 1.21 2020/02/02 23:34:34 tom Exp $
*
* Demonstrate the alloc_pair() function.
*/
#include <test.priv.h>
#include <time.h>
#include <popup_msg.h>
#if HAVE_ALLOC_PAIR && USE_WIDEC_SUPPORT
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAX_BITS 8 /* all but A_ALTCHARSET */
#define MAX_ATTR ((1<<MAX_BITS)-1)
static bool
valid_cap(NCURSES_CONST char *name)
{
char *value = tigetstr(name);
return (value != 0 && value != (char *) -1) ? TRUE : FALSE;
}
static attr_t
next_attr(int now)
{
static bool init = FALSE;
static attr_t table[MAX_BITS * MAX_BITS];
static int limit = 0;
if (!init) {
int j, k;
attr_t bits[MAX_BITS];
init = TRUE;
bits[limit++] = WA_NORMAL;
if (valid_cap("smso"))
bits[limit++] = WA_STANDOUT;
if (valid_cap("smul"))
bits[limit++] = WA_UNDERLINE;
if (valid_cap("rev"))
bits[limit++] = WA_REVERSE;
if (valid_cap("blink"))
bits[limit++] = WA_BLINK;
if (valid_cap("dim"))
bits[limit++] = WA_DIM;
if (valid_cap("bold"))
bits[limit++] = WA_BOLD;
for (j = 0; j < limit; ++j) {
for (k = 0; k < limit; ++k) {
table[j * limit + k] = bits[j] | bits[k];
}
}
}
return table[now % limit];
}
static void
our_content(int pair, int *fg, int *bg)
{
pair %= COLOR_PAIRS;
*fg = (pair / COLORS) % COLORS;
*bg = (pair % COLORS);
}
static int
make_color(int now)
{
int fg, bg;
our_content(now, &fg, &bg);
return alloc_pair(fg, bg);
}
static int
next_color(int now)
{
int result = 0;
if ((short) now > 0) {
if (now < COLOR_PAIRS) {
int fg, bg;
our_content(now, &fg, &bg);
if (init_pair((short) now, (short) fg, (short) bg) != OK)
now = ERR;
} else {
now %= COLOR_PAIRS;
}
result = now;
}
return result;
}
static time_t
now(void)
{
return time((time_t *) 0);
}
static void
usage(void)
{
static const char *msg[] =
{
"Usage: demo_new_pair [options]",
"",
"Repeatedly print using all possible color combinations.",
"",
"Options:",
" -i use init_pair rather than alloc_pair",
" -p start in paged-mode",
" -s start in single-step mode",
" -w print a wide-character cell",
};
unsigned n;
for (n = 0; n < SIZEOF(msg); ++n) {
fprintf(stderr, "%s\n", msg[n]);
}
ExitProgram(EXIT_FAILURE);
}
#define use_pages() \
paged_mode = TRUE, single_mode = TRUE
#define use_single() \
paged_mode = FALSE, single_mode = TRUE
#define update_modes() \
scrollok(stdscr, !paged_mode); \
nodelay(stdscr, !single_mode || paged_mode)
int
main(int argc, char *argv[])
{
static const char *help[] =
{
"This program iterates over the possible color combinations,",
"allocating or initializing color pairs. For best results,",
"choose screen-width dividing evenly into the number of colors,",
"e.g.,",
"",
" 32x64,32x128 256 colors",
" 24x44,24x88 88 colors",
" 32x64,24x128 16 colors",
"",
"Keys:",
" c toggle between coloring and de-coloring cells",
" p show one page at a time",
" s show one character at a time",
" <space> display char/page without pausing",
" v/V cycle through video attributes",
" w toggle between \"#\" and a double-width equivalent",
" ? print this screen (exit on any character).",
"",
"To exit this program, press ^Q, ^[ or \"q\".",
0
};
bool done = FALSE;
bool clobber = FALSE;
bool hascolor = FALSE;
bool use_init = FALSE;
bool use_wide = FALSE;
bool paged_mode = FALSE;
bool single_mode = FALSE;
int video_mode = 0;
int current;
int ch;
wchar_t wch[2];
time_t start = now();
long total_cells = 0;
FILE *output = 0;
setlocale(LC_ALL, "");
while ((ch = getopt(argc, argv, "ipsw")) != -1) {
switch (ch) {
case 'i':
use_init = TRUE;
break;
case 'p':
use_pages();
break;
case 's':
use_single();
break;
case 'w':
use_wide = TRUE;
break;
default:
usage();
break;
}
}
if (isatty(fileno(stderr))) {
output = stderr;
} else if ((ch = open("/dev/tty", O_WRONLY)) >= 0) {
output = fdopen(ch, "w");
} else {
fprintf(stderr, "cannot open terminal for output\n");
ExitProgram(EXIT_FAILURE);
}
if (newterm(NULL, output, stdin) == 0) {
fprintf(stderr, "Cannot initialize terminal\n");
fclose(output);
ExitProgram(EXIT_FAILURE);
}
(void) cbreak(); /* read chars without wait for \n */
(void) noecho(); /* don't echo input */
update_modes();
curs_set(0);
keypad(stdscr, TRUE);
if ((hascolor = has_colors())) {
start_color();
current = 1;
} else {
current = 0;
}
/*
* Repeatedly cycle through all colors, initializing pairs as needed.
* Provide for single-stepping, or page-at-a-time, as well as quitting.
*/
while (!done) {
cchar_t temp;
attr_t my_attrs;
int my_pair;
switch (getch()) {
case HELP_KEY_1:
popup_msg(stdscr, help);
break;
case 'p':
/* step-by-page */
use_pages();
update_modes();
break;
case 's':
/* step-by-char */
use_single();
update_modes();
break;
case ' ':
single_mode = FALSE;
update_modes();
break;
case QUIT:
case ESCAPE:
case 'q':
done = TRUE;
continue;
case 'c':
clobber = !clobber;
continue;
case 'v':
if (--video_mode < 0)
video_mode = MAX_ATTR;
continue;
case 'V':
if (video_mode > MAX_ATTR)
video_mode = 0;
continue;
case 'w':
use_wide = !use_wide;
continue;
case ERR:
break;
default:
beep();
break;
}
if (hascolor) {
my_attrs = next_attr(video_mode);
if (clobber) {
int fg, bg;
our_content(current, &fg, &bg);
my_pair = find_pair(fg, bg);
if (my_pair > 0) {
free_pair(my_pair);
}
my_pair = 0;
} else {
my_pair = (use_init
? next_color(current)
: make_color(current));
}
} else {
my_attrs = next_attr(current);
my_pair = 0;
}
if (my_pair < 0)
break;
wch[0] = use_wide ? 0xff03 : '#';
wch[1] = 0;
setcchar(&temp, wch, my_attrs,
(short) my_pair,
(use_init ? NULL : (void *) &my_pair));
/*
* At the end of a page, move the cursor to the home position.
*/
if ((add_wch(&temp) == ERR) && paged_mode) {
nodelay(stdscr, !single_mode);
move(0, 0);
}
total_cells += 1 + (use_wide ? 1 : 0);
++current;
}
stop_curses();
fclose(output);
printf("%.1f cells/second\n",
(double) (total_cells) / (double) (now() - start));
ExitProgram(EXIT_SUCCESS);
}
#else
int
main(void)
{
printf("This program requires the ncurses alloc_pair function\n");
ExitProgram(EXIT_FAILURE);
}
#endif