Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 1 | /**************************************************************************** |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 2 | * Copyright 2018-2021,2022 Thomas E. Dickey * |
| 3 | * Copyright 2006-2017,2018 Free Software Foundation, Inc. * |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 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 | /* |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 30 | * $Id: savescreen.c,v 1.62 2022/12/10 23:23:27 tom Exp $ |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 31 | * |
| 32 | * Demonstrate save/restore functions from the curses library. |
| 33 | * Thomas Dickey - 2007/7/14 |
| 34 | */ |
| 35 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 36 | #define NEED_TIME_H |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 37 | #include <test.priv.h> |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 38 | #include <popup_msg.h> |
| 39 | #include <parse_rgb.h> |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 40 | |
| 41 | #if HAVE_SCR_DUMP |
| 42 | |
| 43 | #include <sys/types.h> |
| 44 | #include <sys/stat.h> |
| 45 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 46 | #if defined(__hpux) |
| 47 | #define MyMarker 'X' |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 48 | #else |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 49 | #define MyMarker ACS_DIAMOND |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 50 | #endif |
| 51 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 52 | #define MAX_ANSI 8 |
| 53 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 54 | static bool use_init = FALSE; |
| 55 | static bool keep_dumps = FALSE; |
| 56 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 57 | #if USE_WIDEC_SUPPORT |
| 58 | /* In HPUX curses, cchar_t is opaque; other implementations are not */ |
| 59 | static wchar_t |
| 60 | BaseChar(cchar_t data) |
| 61 | { |
| 62 | wchar_t my_wchar[CCHARW_MAX]; |
| 63 | wchar_t result = 0; |
| 64 | attr_t my_attr; |
| 65 | short my_pair; |
| 66 | if (getcchar(&data, my_wchar, &my_attr, &my_pair, NULL) == OK) |
| 67 | result = my_wchar[0]; |
| 68 | return result; |
| 69 | } |
| 70 | #endif |
| 71 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 72 | static int |
| 73 | fexists(const char *name) |
| 74 | { |
| 75 | struct stat sb; |
| 76 | return (stat(name, &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFREG); |
| 77 | } |
| 78 | |
| 79 | static void |
| 80 | setup_next(void) |
| 81 | { |
| 82 | curs_set(1); |
| 83 | reset_shell_mode(); |
| 84 | } |
| 85 | |
| 86 | static void |
| 87 | cleanup(char *files[]) |
| 88 | { |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 89 | if (!keep_dumps) { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 90 | int n; |
| 91 | |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 92 | for (n = 0; files[n] != 0; ++n) { |
| 93 | unlink(files[n]); |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | static int |
| 99 | load_screen(char *filename) |
| 100 | { |
| 101 | int result; |
| 102 | |
| 103 | if (use_init) { |
| 104 | if ((result = scr_init(filename)) != ERR) |
| 105 | result = scr_restore(filename); |
| 106 | } else { |
| 107 | result = scr_set(filename); |
| 108 | } |
| 109 | return result; |
| 110 | } |
| 111 | |
| 112 | /* |
| 113 | * scr_restore() or scr_set() operates on curscr. If we read a character using |
| 114 | * getch() that will refresh stdscr, wiping out the result. To avoid that, |
| 115 | * copy the data back from curscr to stdscr. |
| 116 | */ |
| 117 | static void |
| 118 | after_load(void) |
| 119 | { |
| 120 | overwrite(curscr, stdscr); |
| 121 | doupdate(); |
| 122 | } |
| 123 | |
| 124 | static void |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 125 | show_what(int color, int which, int last) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 126 | { |
| 127 | int y, x, n; |
| 128 | time_t now; |
| 129 | char *mytime; |
| 130 | |
| 131 | getyx(stdscr, y, x); |
| 132 | |
| 133 | move(0, 0); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 134 | printw("Color %d. Saved %d of %d (? for help)", color, which, last + 1); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 135 | |
| 136 | now = time((time_t *) 0); |
| 137 | mytime = ctime(&now); |
| 138 | for (n = (int) strlen(mytime) - 1; n >= 0; --n) { |
| 139 | if (isspace(UChar(mytime[n]))) { |
| 140 | mytime[n] = '\0'; |
| 141 | } else { |
| 142 | break; |
| 143 | } |
| 144 | } |
| 145 | mvprintw(0, (COLS - n - 2), " %s", mytime); |
| 146 | |
| 147 | move(y, x); |
| 148 | |
| 149 | refresh(); |
| 150 | } |
| 151 | |
| 152 | static int |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 153 | get_command(int color, int which, int last) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 154 | { |
| 155 | int ch; |
| 156 | |
| 157 | timeout(50); |
| 158 | |
| 159 | do { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 160 | show_what(color, which, last); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 161 | ch = getch(); |
| 162 | } while (ch == ERR); |
| 163 | |
| 164 | return ch; |
| 165 | } |
| 166 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 167 | static int |
| 168 | dump_screen(char **files, int color, int which, int last, bool use_colors) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 169 | { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 170 | #if USE_WIDEC_SUPPORT |
| 171 | cchar_t mycc; |
| 172 | #endif |
| 173 | char *filename = files[which]; |
| 174 | bool dumped = FALSE; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 175 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 176 | if (filename != 0) { |
| 177 | dumped = TRUE; |
| 178 | show_what(color, ++which, last); |
| 179 | if (scr_dump(filename) == ERR) { |
| 180 | endwin(); |
| 181 | printf("Cannot write screen-dump %s\n", filename); |
| 182 | cleanup(files); |
| 183 | ExitProgram(EXIT_SUCCESS); |
| 184 | } |
| 185 | if (use_colors) { |
| 186 | int cx, cy; |
| 187 | int pair = 1 + (which % MAX_ANSI); |
| 188 | /* |
| 189 | * Change the background color, to make it more obvious. But that |
| 190 | * changes the existing text-color. Copy the old values from the |
| 191 | * currently displayed screen. |
| 192 | */ |
| 193 | bkgd((chtype) COLOR_PAIR(pair)); |
| 194 | for (cy = 1; cy < LINES; ++cy) { |
| 195 | for (cx = 0; cx < COLS; ++cx) { |
| 196 | wmove(curscr, cy, cx); |
| 197 | wmove(stdscr, cy, cx); |
| 198 | #if USE_WIDEC_SUPPORT |
| 199 | if (win_wch(curscr, &mycc) != ERR) { |
| 200 | int myxx = wcwidth(BaseChar(mycc)); |
| 201 | if (myxx > 0) { |
| 202 | wadd_wchnstr(stdscr, &mycc, 1); |
| 203 | cx += (myxx - 1); |
| 204 | } |
| 205 | } |
| 206 | #else |
| 207 | waddch(stdscr, winch(curscr)); |
| 208 | #endif |
| 209 | } |
| 210 | } |
| 211 | } |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 212 | } |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 213 | return dumped; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 214 | } |
| 215 | |
| 216 | static void |
| 217 | editor_help(void) |
| 218 | { |
| 219 | static const char *msgs[] = |
| 220 | { |
| 221 | "You are now in the screen-editor, which allows you to make some", |
| 222 | "lines on the screen, as well as save copies of the screen to a", |
| 223 | "temporary file", |
| 224 | "", |
| 225 | "Keys:", |
| 226 | " q quit", |
| 227 | " n run the screen-loader to show the saved screens", |
| 228 | " <space> dump a screen", |
| 229 | "", |
| 230 | " a toggle between '#' and graphic symbol for drawing", |
| 231 | " c change color drawn by line to next in palette", |
| 232 | " h,j,k,l or arrows to move around the screen, drawing", |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 233 | 0 |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 234 | }; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 235 | popup_msg(stdscr, msgs); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | static void |
| 239 | replay_help(void) |
| 240 | { |
| 241 | static const char *msgs[] = |
| 242 | { |
| 243 | "You are now in the screen-loader, which allows you to view", |
| 244 | "the dumped/restored screens.", |
| 245 | "", |
| 246 | "Keys:", |
| 247 | " q quit", |
| 248 | " <space> load the next screen", |
| 249 | " <backspace> load the previous screen", |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 250 | 0 |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 251 | }; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 252 | popup_msg(stdscr, msgs); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 253 | } |
| 254 | |
| 255 | static void |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 256 | usage(int ok) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 257 | { |
| 258 | static const char *msg[] = |
| 259 | { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 260 | "Usage: savescreen [-r] files" |
| 261 | ,"" |
| 262 | ,USAGE_COMMON |
| 263 | ,"Options:" |
| 264 | ," -f file fill/initialize screen using text from this file" |
| 265 | ," -i use scr_init/scr_restore rather than scr_set" |
| 266 | ," -k keep the restored dump-files rather than removing them" |
| 267 | ," -r replay the screen-dump files" |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 268 | }; |
| 269 | unsigned n; |
| 270 | for (n = 0; n < SIZEOF(msg); ++n) { |
| 271 | fprintf(stderr, "%s\n", msg[n]); |
| 272 | } |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 273 | ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 274 | } |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 275 | /* *INDENT-OFF* */ |
| 276 | VERSION_COMMON() |
| 277 | /* *INDENT-ON* */ |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 278 | |
| 279 | int |
| 280 | main(int argc, char *argv[]) |
| 281 | { |
| 282 | int ch; |
| 283 | int which = 0; |
| 284 | int last; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 285 | bool use_colors = FALSE; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 286 | bool replaying = FALSE; |
| 287 | bool done = FALSE; |
| 288 | char **files; |
| 289 | char *fill_by = 0; |
| 290 | #if USE_WIDEC_SUPPORT |
| 291 | cchar_t mycc; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 292 | static const wchar_t mywc[2] = |
| 293 | {L'#', 0}; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 294 | #endif |
| 295 | |
| 296 | setlocale(LC_ALL, ""); |
| 297 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 298 | while ((ch = getopt(argc, argv, OPTS_COMMON "f:ikr")) != -1) { |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 299 | switch (ch) { |
| 300 | case 'f': |
| 301 | fill_by = optarg; |
| 302 | break; |
| 303 | case 'i': |
| 304 | use_init = TRUE; |
| 305 | break; |
| 306 | case 'k': |
| 307 | keep_dumps = TRUE; |
| 308 | break; |
| 309 | case 'r': |
| 310 | replaying = TRUE; |
| 311 | break; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 312 | case OPTS_VERSION: |
| 313 | show_version(argv); |
| 314 | ExitProgram(EXIT_SUCCESS); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 315 | default: |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 316 | usage(ch == OPTS_USAGE); |
| 317 | /* NOTREACHED */ |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 318 | } |
| 319 | } |
| 320 | |
| 321 | files = argv + optind; |
| 322 | last = argc - optind - 1; |
| 323 | |
| 324 | if (replaying) { |
| 325 | while (last >= 0 && !fexists(files[last])) |
| 326 | --last; |
| 327 | } |
| 328 | |
| 329 | initscr(); |
| 330 | cbreak(); |
| 331 | noecho(); |
| 332 | keypad(stdscr, TRUE); |
| 333 | curs_set(0); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 334 | |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 335 | if (has_colors() && (start_color() == OK) && COLORS >= MAX_ANSI) { |
| 336 | #if USE_WIDEC_SUPPORT |
| 337 | bool using_rgb = FALSE; |
| 338 | #endif |
| 339 | static const struct { |
| 340 | int fg, bg; |
| 341 | } table[MAX_ANSI] = { |
| 342 | #define DATA(fg,bg) { COLOR_##fg, COLOR_##bg } |
| 343 | DATA(RED, WHITE), |
| 344 | DATA(GREEN, WHITE), |
| 345 | DATA(YELLOW, BLACK), |
| 346 | DATA(BLUE, WHITE), |
| 347 | DATA(MAGENTA, WHITE), |
| 348 | DATA(MAGENTA, BLACK), |
| 349 | DATA(CYAN, WHITE), |
| 350 | DATA(CYAN, BLACK), |
| 351 | #undef DATA |
| 352 | }; |
| 353 | int n; |
| 354 | int pair = 1; |
| 355 | |
| 356 | use_colors = TRUE; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 357 | /* |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 358 | * Discounting color-pair 0 (no color), make the next 8 color pairs |
| 359 | * useful for leaving a visually distinct trail of characters on the |
| 360 | * screen. |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 361 | */ |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 362 | for (n = 0; n < MAX_ANSI; ++n) { |
| 363 | init_pair((short) pair++, (short) table[n].fg, (short) table[n].bg); |
| 364 | } |
| 365 | /* |
| 366 | * After that, use color pairs for constructing a test-pattern, e.g., |
| 367 | * imitating xterm's scripts. |
| 368 | */ |
| 369 | if (fill_by == 0) { |
| 370 | if (COLORS <= 256) { |
| 371 | for (n = 0; n < COLORS; ++n) |
| 372 | init_pair((short) (n + MAX_ANSI), (short) n, (short) n); |
| 373 | } |
| 374 | #if HAVE_TIGETSTR && USE_WIDEC_SUPPORT |
| 375 | else { |
| 376 | int r_max, g_max, b_max; |
| 377 | |
| 378 | if (parse_rgb(&r_max, &g_max, &b_max) > 0) { |
| 379 | int rows = LINES - 1; |
| 380 | int cols = COLS - 1; |
| 381 | int b_delta = (b_max / rows); |
| 382 | int r_delta = (r_max / cols); |
| 383 | int g_delta = (g_max / cols); |
| 384 | int row = 0; |
| 385 | int b = 0; |
| 386 | |
| 387 | using_rgb = TRUE; |
| 388 | while (row++ < rows) { |
| 389 | int col = 0; |
| 390 | int r = 0; |
| 391 | int g = g_max; |
| 392 | while (col++ < cols) { |
| 393 | int color = (((r * (g_max + 1)) + g) * (b_max + 1) |
| 394 | + b + MAX_ANSI); |
| 395 | #if USE_EXTENDED_COLOR |
| 396 | init_extended_pair(pair, color, color); |
| 397 | #else |
| 398 | init_pair(pair, color, color); |
| 399 | #endif |
| 400 | pair++; |
| 401 | r += r_delta; |
| 402 | g -= g_delta; |
| 403 | } |
| 404 | b += b_delta; |
| 405 | } |
| 406 | } |
| 407 | } |
| 408 | #endif |
| 409 | } |
| 410 | if ((fill_by == 0) && !replaying) { |
| 411 | #if USE_WIDEC_SUPPORT |
| 412 | int cube = 0; |
| 413 | #endif |
| 414 | /* |
| 415 | * Originally (before wide-characters) ncurses supported 16 colors. |
| 416 | */ |
| 417 | if (COLORS >= 16 && COLORS <= 256) { |
| 418 | mvprintw(2, 0, "System colors:\n"); |
| 419 | for (n = 0; n < 16; ++n) { |
| 420 | pair = n + MAX_ANSI; |
| 421 | addch((chtype) (' ' | COLOR_PAIR(pair))); |
| 422 | addch((chtype) (' ' | COLOR_PAIR(pair))); |
| 423 | if (((n + 1) % 8) == 0) |
| 424 | addch('\n'); |
| 425 | } |
| 426 | } |
| 427 | /* |
| 428 | * Even with ncurses, you need wide-character support to have more |
| 429 | * than 16 colors. |
| 430 | */ |
| 431 | #if USE_WIDEC_SUPPORT |
| 432 | if (COLORS == 88) { |
| 433 | cube = 4; |
| 434 | } else if (COLORS == 256) { |
| 435 | cube = 6; |
| 436 | } |
| 437 | if (cube != 0) { |
| 438 | int r, g, b; |
| 439 | int cube0 = 16; |
| 440 | int cube1 = cube0 + (cube * cube * cube); |
| 441 | |
| 442 | addch('\n'); |
| 443 | printw("Color cube, %dx%dx%d:\n", cube, cube, cube); |
| 444 | for (g = 0; g < cube; g++) { |
| 445 | for (r = 0; r < cube; r++) { |
| 446 | for (b = 0; b < cube; b++) { |
| 447 | pair = MAX_ANSI |
| 448 | + 16 |
| 449 | + (r * cube * cube) + (g * cube) + b; |
| 450 | setcchar(&mycc, mywc, 0, (short) pair, NULL); |
| 451 | add_wch(&mycc); |
| 452 | add_wch(&mycc); |
| 453 | } |
| 454 | addch(' '); |
| 455 | } |
| 456 | addch('\n'); |
| 457 | } |
| 458 | addch('\n'); |
| 459 | printw("Grayscale ramp:\n"); |
| 460 | for (n = cube1; n < COLORS; ++n) { |
| 461 | pair = n + MAX_ANSI; |
| 462 | setcchar(&mycc, mywc, 0, (short) pair, NULL); |
| 463 | add_wch(&mycc); |
| 464 | add_wch(&mycc); |
| 465 | } |
| 466 | } else if ((COLORS > 256) && using_rgb) { |
| 467 | int rows = LINES - 1; |
| 468 | int cols = COLS - 1; |
| 469 | int row = 0; |
| 470 | |
| 471 | pair = MAX_ANSI; |
| 472 | while (row++ < rows) { |
| 473 | int col = 0; |
| 474 | while (col++ < cols) { |
| 475 | setcchar(&mycc, mywc, 0, (short) pair, &pair); |
| 476 | add_wch(&mycc); |
| 477 | ++pair; |
| 478 | } |
| 479 | addch('\n'); |
| 480 | } |
| 481 | addch('\n'); |
| 482 | } |
| 483 | #endif |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 484 | } |
| 485 | } |
| 486 | |
| 487 | if (fill_by != 0) { |
| 488 | FILE *fp = fopen(fill_by, "r"); |
| 489 | if (fp != 0) { |
| 490 | bool filled = FALSE; |
| 491 | move(1, 0); |
| 492 | while ((ch = fgetc(fp)) != EOF) { |
| 493 | if (addch(UChar(ch)) == ERR) { |
| 494 | filled = TRUE; |
| 495 | break; |
| 496 | } |
| 497 | } |
| 498 | fclose(fp); |
| 499 | if (!filled) { |
| 500 | while (addch(' ') != ERR) { |
| 501 | ; |
| 502 | } |
| 503 | } |
| 504 | move(0, 0); |
| 505 | } else { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 506 | stop_curses(); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 507 | fprintf(stderr, "Cannot open \"%s\"\n", fill_by); |
| 508 | ExitProgram(EXIT_FAILURE); |
| 509 | } |
| 510 | } |
| 511 | |
| 512 | if (replaying) { |
| 513 | |
| 514 | /* |
| 515 | * Use the last file as the initial/current screen. |
| 516 | */ |
| 517 | if (last < 0) { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 518 | stop_curses(); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 519 | printf("No screen-dumps given\n"); |
| 520 | ExitProgram(EXIT_FAILURE); |
| 521 | } |
| 522 | |
| 523 | which = last; |
| 524 | if (load_screen(files[which]) == ERR) { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 525 | stop_curses(); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 526 | printf("Cannot load screen-dump %s\n", files[which]); |
| 527 | ExitProgram(EXIT_FAILURE); |
| 528 | } |
| 529 | after_load(); |
| 530 | |
| 531 | while (!done && (ch = getch()) != ERR) { |
| 532 | switch (ch) { |
| 533 | case 'n': |
| 534 | /* |
| 535 | * If we got a "next" here, skip to the final screen before |
| 536 | * moving to the next process. |
| 537 | */ |
| 538 | setup_next(); |
| 539 | which = last; |
| 540 | done = TRUE; |
| 541 | break; |
| 542 | case 'q': |
| 543 | cleanup(files); |
| 544 | done = TRUE; |
| 545 | break; |
| 546 | case KEY_BACKSPACE: |
| 547 | case '\b': |
| 548 | if (--which < 0) |
| 549 | which = last; |
| 550 | break; |
| 551 | case ' ': |
| 552 | if (++which > last) |
| 553 | which = 0; |
| 554 | break; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 555 | case HELP_KEY_1: |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 556 | replay_help(); |
| 557 | break; |
| 558 | default: |
| 559 | beep(); |
| 560 | continue; |
| 561 | } |
| 562 | |
| 563 | if (ch == 'q') { |
| 564 | ; |
| 565 | } else if (scr_restore(files[which]) == ERR) { |
| 566 | endwin(); |
| 567 | printf("Cannot load screen-dump %s\n", files[which]); |
| 568 | cleanup(files); |
| 569 | ExitProgram(EXIT_FAILURE); |
| 570 | } else { |
| 571 | wrefresh(curscr); |
| 572 | } |
| 573 | } |
| 574 | endwin(); |
| 575 | } else { |
| 576 | int y = 0; |
| 577 | int x = 0; |
| 578 | int color = 0; |
| 579 | int altchars = 0; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 580 | bool dirty = use_colors || (fill_by != 0); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 581 | |
| 582 | while (!done) { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 583 | switch (get_command(color, which, last)) { |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 584 | case 'n': |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 585 | if (dirty && files[which]) { |
| 586 | dump_screen(files, color, which, last, use_colors); |
| 587 | } |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 588 | setup_next(); |
| 589 | done = TRUE; |
| 590 | break; |
| 591 | case 'q': |
| 592 | cleanup(files); |
| 593 | done = TRUE; |
| 594 | break; |
| 595 | case ' ': |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 596 | if (dump_screen(files, color, which, last, use_colors)) { |
| 597 | which = (which + 1) % MAX_ANSI; |
| 598 | dirty = FALSE; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 599 | } else { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 600 | setup_next(); |
| 601 | done = TRUE; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 602 | } |
| 603 | break; |
| 604 | case KEY_LEFT: |
| 605 | case 'h': |
| 606 | if (--x < 0) |
| 607 | x = COLS - 1; |
| 608 | break; |
| 609 | case KEY_DOWN: |
| 610 | case 'j': |
| 611 | if (++y >= LINES) |
| 612 | y = 1; |
| 613 | break; |
| 614 | case KEY_UP: |
| 615 | case 'k': |
| 616 | if (--y < 1) |
| 617 | y = LINES - 1; |
| 618 | break; |
| 619 | case KEY_RIGHT: |
| 620 | case 'l': |
| 621 | if (++x >= COLS) |
| 622 | x = 0; |
| 623 | break; |
| 624 | case 'a': |
| 625 | altchars = !altchars; |
| 626 | break; |
| 627 | case 'c': |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 628 | if (use_colors) { |
| 629 | color = (color + 1) % MAX_ANSI; |
| 630 | } |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 631 | break; |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 632 | case HELP_KEY_1: |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 633 | editor_help(); |
| 634 | break; |
| 635 | default: |
| 636 | beep(); |
| 637 | continue; |
| 638 | } |
| 639 | if (!done) { |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 640 | chtype attr = A_REVERSE; |
| 641 | chtype ch2 = (altchars ? MyMarker : '#'); |
| 642 | if (use_colors) { |
| 643 | attr |= (chtype) COLOR_PAIR(color); |
| 644 | } |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 645 | move(y, x); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 646 | AddCh(ch2 | attr); |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 647 | move(y, x); |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 648 | dirty = TRUE; |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 649 | } |
| 650 | } |
| 651 | endwin(); |
| 652 | } |
| 653 | ExitProgram(EXIT_SUCCESS); |
| 654 | } |
| 655 | |
| 656 | #else |
| 657 | int |
micky387 | 9b9f5e7 | 2025-07-08 18:04:53 -0400 | [diff] [blame] | 658 | main(void) |
Steve Kondik | ae271bc | 2015-11-15 02:50:53 +0100 | [diff] [blame] | 659 | { |
| 660 | printf("This program requires the screen-dump functions\n"); |
| 661 | ExitProgram(EXIT_FAILURE); |
| 662 | } |
| 663 | #endif |