Annotation of brogue-ce/src/platform/term.c, Revision 1.1
1.1 ! rubenllo 1: #include <ncurses.h>
! 2: #include "term.h"
! 3: #include <math.h>
! 4: #include <stdlib.h>
! 5: #include <string.h>
! 6:
! 7:
! 8: // As a rule, everything in term.c is the result of gradual evolutionary
! 9: // change. It's messy.
! 10:
! 11: #define COLORING(fg,bg) (((fg) & 0x0f) | (((bg) & 0x07) << 4))
! 12: #define COLOR_FG(color,fg) (((fg) & 0x0f) + ((color) & 0x70))
! 13: #define COLOR_BG(color,bg) (((color) & 0x0f) + (((bg) & 0x07) << 4))
! 14: #define COLOR_INDEX(color) (1 + ((color)&0x07) + (((color) >> 1) & 0x38))
! 15: #define COLOR_ATTR(color) (COLOR_PAIR(COLOR_INDEX(color)) | (((color)&0x08) ? A_BOLD : 0))
! 16:
! 17:
! 18: static struct { int curses, color; } videomode = { 0, 0 };
! 19:
! 20: static struct { int width, height; } minsize = { 80, 24 };
! 21:
! 22: static void init_coersion();
! 23:
! 24:
! 25: // 256 color mode stuff
! 26: static void initialize_prs();
! 27:
! 28: typedef struct {
! 29: int r, g, b, idx;
! 30: } intcolor;
! 31:
! 32: struct {
! 33: intcolor fore, back;
! 34: int count, next;
! 35: } prs[256];
! 36:
! 37:
! 38: typedef struct {
! 39: int ch, pair, shuffle;
! 40: intcolor fore, back;
! 41: } pairmode_cell;
! 42:
! 43: pairmode_cell *cell_buffer;
! 44:
! 45: enum {
! 46: coerce_16,
! 47: coerce_256
! 48: } colormode;
! 49:
! 50: int is_xterm;
! 51:
! 52:
! 53: //
! 54:
! 55: static void preparecolor ( ) {
! 56: // sixteen color mode colors (we use these in 256-color mode, too)
! 57: static int pairParts[8] = {
! 58: COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
! 59: COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
! 60: };
! 61:
! 62: int fg, bg;
! 63: for (bg=0; bg<8; bg++) {
! 64: for (fg=0; fg<8; fg++) {
! 65: init_pair(
! 66: COLOR_INDEX(COLORING(fg, bg)),
! 67: pairParts[fg], pairParts[bg]
! 68: );
! 69: }
! 70: }
! 71:
! 72: if (COLORS >= 256) {
! 73: colormode = coerce_256;
! 74: }
! 75: }
! 76:
! 77: static void term_title(const char *title) {
! 78: if (is_xterm) {
! 79: printf ("\033]2;%s\007", title); // ESC ]0; title BEL
! 80: }
! 81: }
! 82:
! 83: static void term_title_pop() {
! 84: if (is_xterm) {
! 85: term_title("Terminal");
! 86: printf ("\033[22;2t");
! 87: }
! 88: }
! 89: static void term_title_push() {
! 90: if (is_xterm) {
! 91: printf ("\033[23;2t");
! 92: }
! 93: }
! 94:
! 95: static void term_set_size(int h, int w) {
! 96: // works in gnome-terminal, but not xterm; causes trouble for maximized windows
! 97: if (is_xterm) {
! 98: // first, try resizing the height, in case only that is supported
! 99: printf ("\033[%dt", (h > 24 ? h : 24));
! 100:
! 101: // then try resizing both, in case we can
! 102: printf ("\033[8;%d;%dt", h, w);
! 103:
! 104: // then refresh so ncurses knows about it
! 105: refresh( );
! 106: }
! 107: }
! 108:
! 109: static void term_show_scrollbar(int show) {
! 110: // works in xterm, but not gnome-terminal
! 111: if (is_xterm) {
! 112: if (show) {
! 113: printf ("\033[?30h");
! 114: } else {
! 115: printf ("\033[?30l");
! 116: }
! 117: }
! 118: }
! 119:
! 120: static int curses_init( ) {
! 121: if (videomode.curses) return 0;
! 122:
! 123: // isterm?
! 124: initscr( );
! 125: if (!has_colors( )) {
! 126: endwin( );
! 127: fprintf (stderr, "Your terminal has no color support.\n");
! 128: return 1;
! 129: }
! 130:
! 131: start_color( );
! 132: clear( );
! 133: curs_set( 0 );
! 134: refresh( );
! 135: leaveok(stdscr, TRUE);
! 136: preparecolor( );
! 137: cbreak( );
! 138: noecho( );
! 139:
! 140: nodelay(stdscr, TRUE);
! 141: meta(stdscr, TRUE);
! 142: keypad(stdscr, TRUE);
! 143:
! 144: mousemask(BUTTON1_PRESSED | BUTTON1_RELEASED | REPORT_MOUSE_POSITION | BUTTON_SHIFT | BUTTON_CTRL, NULL);
! 145: mouseinterval(0); //do no click processing, thank you
! 146:
! 147: videomode.curses = 1;
! 148:
! 149: getmaxyx(stdscr, Term.height, Term.width);
! 150:
! 151: return 1;
! 152: }
! 153:
! 154:
! 155: static int term_start() {
! 156: char *term = getenv("TERM");
! 157: is_xterm = (strncmp(term, "xterm", 5) == 0) || (strncmp(term, "gnome", 5) == 0) || (strncmp(term, "st", 2) == 0);
! 158:
! 159: term_title_push();
! 160: term_show_scrollbar(0);
! 161:
! 162: int ok = curses_init();
! 163: init_coersion();
! 164:
! 165: return ok;
! 166: }
! 167:
! 168: static void term_end() {
! 169: term_title_pop();
! 170: clear();
! 171: refresh();
! 172: endwin();
! 173: }
! 174:
! 175: typedef struct CIE {
! 176: float X, Y, Z;
! 177: float x, y, z;
! 178: } CIE;
! 179:
! 180: typedef struct Lab {
! 181: float L, a, b;
! 182: } Lab;
! 183:
! 184: #define DARK 0.0
! 185: #define DIM 0.1
! 186: #define MID 0.3
! 187: #define HALFBRIGHT 0.5
! 188: #define BRIGHT 0.9
! 189:
! 190: fcolor palette[16] = {
! 191: {DARK, DARK, DARK},
! 192: {MID, DARK, DARK},
! 193: {DARK, MID, DARK},
! 194: {MID, .8 * MID, DIM},
! 195: {DARK, DARK, MID},
! 196: {MID + DIM, DARK, MID},
! 197: {DARK, MID, MID},
! 198: {HALFBRIGHT, HALFBRIGHT, HALFBRIGHT},
! 199:
! 200: {MID, MID, MID},
! 201: {BRIGHT, DARK, DARK},
! 202: {DARK, BRIGHT, DARK},
! 203: {BRIGHT, BRIGHT, DARK},
! 204: {HALFBRIGHT, MID, BRIGHT},
! 205: {BRIGHT, HALFBRIGHT, BRIGHT},
! 206: {DARK, BRIGHT, BRIGHT},
! 207: {BRIGHT, BRIGHT, BRIGHT}
! 208: };
! 209:
! 210: CIE ciePalette[16];
! 211: Lab labPalette[16];
! 212: CIE adamsPalette[16];
! 213:
! 214: static CIE white;
! 215:
! 216: static CIE toCIE(fcolor c) {
! 217: double a = 0.055;
! 218:
! 219: // http://en.wikipedia.org/wiki/SRGB_color_space#The_reverse_transformation
! 220:
! 221: c.r = c.r <= 0.04045 ? c.r / 12.92 : pow((c.r + a) / (1 + a), 2.4);
! 222: c.g = c.g <= 0.04045 ? c.g / 12.92 : pow((c.g + a) / (1 + a), 2.4);
! 223: c.b = c.b <= 0.04045 ? c.b / 12.92 : pow((c.b + a) / (1 + a), 2.4);
! 224:
! 225: CIE cie;
! 226: cie.X = 0.4124 * c.r + 0.3576 * c.g + 0.1805 * c.b;
! 227: cie.Y = 0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b;
! 228: cie.Z = 0.0193 * c.r + 0.1192 * c.g + 0.9505 * c.b;
! 229:
! 230: float sum = cie.X + cie.Y + cie.Z;
! 231: if (sum == 0.0) sum = 1.0;
! 232: cie.x = cie.X / sum;
! 233: cie.y = cie.Y / sum;
! 234: cie.z = 1.0 - cie.x - cie.y;
! 235:
! 236: return cie;
! 237: }
! 238:
! 239: static float Labf(float t) {
! 240: return t > ((6.0/29.0) * (6.0/29.0) * (6.0/29.0)) ? pow(t, 1.0/3.0) : ((1.0/3.0) * (29.0 / 6.0) * (29.0 / 6.0)) * t + (4.0 / 29.0);
! 241: }
! 242:
! 243: static Lab toLab(CIE *c) {
! 244: CIE n = (CIE) {Labf(c->X / white.X), Labf(c->Y / white.Y), Labf(c->Z / white.Z)};
! 245: Lab l;
! 246:
! 247: // http://en.wikipedia.org/wiki/L*a*b*#RGB_and_CMYK_conversions
! 248: l.L = 116.0 * n.Y - 16;
! 249: l.a = 500.0 * (n.X - n.Y);
! 250: l.b = 200.0 * (n.Y - n.Z);
! 251:
! 252: return l;
! 253: }
! 254:
! 255: static float munsellSloanGodlove(float t) {
! 256: return sqrt(1.4742 * t - 0.004743 * t * t);
! 257: }
! 258:
! 259: static CIE adams(CIE *v) {
! 260: CIE c;
! 261: c.Y = munsellSloanGodlove(v->Y);
! 262: c.X = munsellSloanGodlove((white.Y / white.X) * v->X) - c.Y;
! 263: c.Z = munsellSloanGodlove((white.Z / white.X) * v->Z) - c.Y;
! 264:
! 265: return c;
! 266: }
! 267:
! 268: #define SQUARE(x) ((x) * (x))
! 269:
! 270: static float CIE76(Lab *L1, Lab *L2) {
! 271: // http://en.wikipedia.org/wiki/Color_difference#CIE76
! 272: float lbias = 1.0;
! 273: return sqrt(lbias * SQUARE(L2->L - L1->L) + SQUARE(L2->a - L1->a) + SQUARE(L2->b - L1->b));
! 274: }
! 275:
! 276: static void init_coersion() {
! 277: fcolor sRGB_white = (fcolor) {1, 1, 1};
! 278: white = toCIE(sRGB_white);
! 279:
! 280: int i;
! 281: for (i = 0; i < 16; i++) {
! 282: ciePalette[i] = toCIE(palette[i]);
! 283: labPalette[i] = toLab(&ciePalette[i]);
! 284: adamsPalette[i] = adams(&ciePalette[i]);
! 285: }
! 286:
! 287: if (colormode == coerce_256) {
! 288: initialize_prs();
! 289: }
! 290:
! 291: cell_buffer = 0;
! 292: }
! 293:
! 294: static int best (fcolor *fg, fcolor *bg) {
! 295: // analyze fg & bg for their contrast
! 296: CIE cieFg = toCIE(*fg);
! 297: CIE cieBg = toCIE(*bg);
! 298: Lab labFg = toLab(&cieFg);
! 299: Lab labBg = toLab(&cieBg);
! 300: // CIE adamsFg = adams(&cieFg);
! 301: // CIE adamsBg = adams(&cieBg);
! 302:
! 303: float JND = 2.3; // just-noticeable-difference
! 304: int areTheSame = CIE76(&labFg, &labBg) <= 2.0 * JND; // a little extra fudge
! 305:
! 306: float big = 100000000;
! 307: int fg1 = 0, fg2 = 0, bg1 = 0, bg2 = 0;
! 308: float fg1_score = big, fg2_score = big;
! 309: float bg1_score = big, bg2_score = big;
! 310:
! 311: int i;
! 312:
! 313: for (i = 0; i < 8; i++) {
! 314: float s = CIE76(labPalette + i, &labBg);
! 315:
! 316: if (s < bg2_score) {
! 317: if (s < bg1_score) {
! 318: bg2 = bg1; bg1 = i;
! 319: bg2_score = bg1_score; bg1_score = s;
! 320: } else {
! 321: bg2 = i; bg2_score = s;
! 322: }
! 323: }
! 324: }
! 325:
! 326: if (areTheSame) {
! 327: return COLORING(bg1, bg1);
! 328: }
! 329:
! 330: for (i = 0; i < 16; i++) {
! 331: float s = CIE76(labPalette + i, &labFg);
! 332:
! 333: if (s < fg2_score) {
! 334: if (s < fg1_score) {
! 335: fg2 = fg1; fg1 = i;
! 336: fg2_score = fg1_score; fg1_score = s;
! 337: } else {
! 338: fg2 = i; fg2_score = s;
! 339: }
! 340: }
! 341: }
! 342:
! 343: if (fg1 != bg1) {
! 344: return COLORING (fg1, bg1);
! 345: } else {
! 346: if (fg1_score + bg2_score < fg2_score + bg1_score) {
! 347: return COLORING(fg1, bg2);
! 348: } else {
! 349: return COLORING(fg2, bg1);
! 350: }
! 351: }
! 352: }
! 353:
! 354:
! 355:
! 356:
! 357: static void initialize_prs() {
! 358: int i;
! 359: for (i = 16; i < 255; i++) {
! 360: prs[i].next = i + 1;
! 361: }
! 362: prs[0].next = 16;
! 363: prs[1].next = 0;
! 364: prs[255].next = 0;
! 365: }
! 366:
! 367: static void coerce_colorcube (fcolor *f, intcolor *c) {
! 368: // 0-15 are the standard ANSI colors
! 369: // 16-231 are a 6x6x6 RGB color cube given by ((36 * r) + (6 * g) + b + 16) with r,g,b in [0..5]
! 370: // 232-255 are a greyscale ramp without black and white.
! 371:
! 372: float sat = 0.2, bright = 0.6, contrast = 6.3;
! 373:
! 374: float rf = bright + f->r * contrast,
! 375: gf = bright + f->g * contrast,
! 376: bf = bright + f->b * contrast;
! 377:
! 378: if (rf < gf && rf < bf) rf -= sat * ((gf < bf ? bf : gf) - rf);
! 379: else if (gf < bf && gf < rf) gf -= sat * ((rf < bf ? bf : rf) - gf);
! 380: else if (bf < gf && bf < rf) bf -= sat * ((gf < rf ? rf : gf) - bf);
! 381:
! 382: int r = rf, g = gf, b = bf;
! 383: r = r < 0 ? 0 : r > 5 ? 5 : r;
! 384: g = g < 0 ? 0 : g > 5 ? 5 : g;
! 385: b = b < 0 ? 0 : b > 5 ? 5 : b;
! 386:
! 387: c->r = r;
! 388: c->g = g;
! 389: c->b = b;
! 390: c->idx = ((36 * r) + (6 * g) + b + 16);
! 391: }
! 392:
! 393: static int intcolor_distance (intcolor *a, intcolor *b) {
! 394: return
! 395: (a->r - b->r) * (a->r - b->r)
! 396: + (a->g - b->g) * (a->g - b->g)
! 397: + (a->b - b->b) * (a->b - b->b);
! 398: }
! 399:
! 400: static int coerce_prs (intcolor *fg, intcolor *bg) {
! 401: // search for an exact match in the list
! 402: int pair;
! 403: pair = prs[1].next;
! 404: while (pair) {
! 405: if (prs[pair].fore.idx == fg->idx && prs[pair].back.idx == bg->idx) {
! 406: // perfect.
! 407: prs[pair].count++;
! 408: return pair;
! 409: }
! 410: pair = prs[pair].next;
! 411: }
! 412:
! 413: // no exact match? try to insert it as a new one
! 414: pair = prs[0].next;
! 415: if (pair) {
! 416: // there's room!
! 417:
! 418: // remove
! 419: prs[0].next = prs[pair].next;
! 420:
! 421: // insert at the front
! 422: prs[pair].next = prs[1].next;
! 423: prs[1].next = pair;
! 424:
! 425: // initialize it
! 426: prs[pair].fore = *fg;
! 427: prs[pair].back = *bg;
! 428: prs[pair].count = 1;
! 429:
! 430: init_pair(pair, fg->idx, bg->idx);
! 431:
! 432: return pair;
! 433: }
! 434:
! 435: // search for an approximate match in the list
! 436: int bestpair = 0, bestscore = 2 * 3 * 6 * 6; // naive distance metric for now
! 437: pair = prs[1].next;
! 438: while (pair) {
! 439: int delta = intcolor_distance(&prs[pair].fore, fg) + intcolor_distance(&prs[pair].back, bg);
! 440: if (delta < bestscore) {
! 441: bestscore = delta;
! 442: bestpair = pair;
! 443: if (delta == 1) break; // as good as it gets without being exact!
! 444: }
! 445: pair = prs[pair].next;
! 446: }
! 447:
! 448: prs[bestpair].count++;
! 449: return bestpair;
! 450: }
! 451:
! 452: static void buffer_plot(int ch, int x, int y, fcolor *fg, fcolor *bg) {
! 453: // int pair = 256 + x + y * minsize.width;
! 454: // intcolor cube_fg, cube_bg;
! 455: // coerce_colorcube(fg, &cube_fg),
! 456: // coerce_colorcube(bg, &cube_bg);
! 457:
! 458: // pair = cube_bg.idx;
! 459: // cube_fg = cube_bg;
! 460:
! 461:
! 462: // init_pair(pair, cube_fg.idx, cube_bg.idx);
! 463:
! 464: // return pair;
! 465:
! 466: intcolor cube_fg, cube_bg;
! 467:
! 468: coerce_colorcube(fg, &cube_fg);
! 469: coerce_colorcube(bg, &cube_bg);
! 470: if (cube_fg.idx == cube_bg.idx) {
! 471: // verify that the colors are really the same; otherwise, we'd better force the output apart
! 472: int naive_distance =
! 473: (fg->r - bg->r) * (fg->r - bg->r)
! 474: + (fg->g - bg->g) * (fg->g - bg->g)
! 475: + (fg->b - bg->b) * (fg->b - bg->b);
! 476: if (naive_distance > 3) {
! 477: // very arbitrary cutoff, and an arbitrary fix, very lazy
! 478: if (cube_bg.r > 0) {cube_bg.r -= 1; cube_bg.idx -= 1; }
! 479: if (cube_bg.g > 0) {cube_bg.g -= 1; cube_bg.idx -= 6; }
! 480: if (cube_bg.b > 0) {cube_bg.b -= 1; cube_bg.idx -= 36; }
! 481: }
! 482: }
! 483:
! 484: int cell = x + y * minsize.width;
! 485: cell_buffer[cell].ch = ch;
! 486: cell_buffer[cell].pair = -1;
! 487: cell_buffer[cell].fore = cube_fg;
! 488: cell_buffer[cell].back = cube_bg;
! 489: }
! 490:
! 491: static void buffer_render_256() {
! 492: // build a new palette
! 493: initialize_prs();
! 494:
! 495: int length = minsize.width * minsize.height;
! 496: int i, idx, x, y;
! 497:
! 498: for (i = 0; i < length; i++) {
! 499: cell_buffer[i].shuffle = i;
! 500: }
! 501: for (i = length - 1; i >= 0; i--) {
! 502: // int roll = i == 0 ? 0 : rand() % i;
! 503: // idx = cell_buffer[roll].shuffle;
! 504:
! 505: // cell_buffer[roll].shuffle = cell_buffer[i].shuffle;
! 506:
! 507: idx = i;
! 508:
! 509: int pair = coerce_prs(&cell_buffer[idx].fore, &cell_buffer[idx].back);
! 510: cell_buffer[idx].pair = pair;
! 511: }
! 512:
! 513: // render it all!
! 514: i = 0;
! 515: for (y = 0; y < minsize.height; y++) {
! 516: move(y, 0);
! 517: for (x = 0; x < minsize.width; x++) {
! 518: color_set(cell_buffer[i].pair, NULL);
! 519: addch(cell_buffer[i].ch);
! 520: i++;
! 521: }
! 522: }
! 523: }
! 524:
! 525: static void term_mvaddch(int x, int y, int ch, fcolor *fg, fcolor *bg) {
! 526: if (x < 0 || y < 0 || x >= minsize.width || y >= minsize.height) return;
! 527:
! 528: if (colormode == coerce_16) {
! 529: int c = best(fg, bg);
! 530: attrset(COLOR_ATTR(c));
! 531: mvaddch(y, x, ch);
! 532: } else {
! 533: buffer_plot(ch, x, y, fg, bg);
! 534: }
! 535: }
! 536:
! 537: static void term_refresh() {
! 538: // to set up a 256-color terminal, see:
! 539: // http://push.cx/2008/256-color-xterms-in-ubuntu
! 540: if (0 && can_change_color()) {
! 541: int i;
! 542: for (i = 0; i < 16; i++) {
! 543: short r = palette[i].r * 1000;
! 544: short g = palette[i].g * 1000;
! 545: short b = palette[i].b * 1000;
! 546: if (r < 0) r = 0;
! 547: if (g < 0) g = 0;
! 548: if (b < 0) b = 0;
! 549: init_color(i + 1, r, g, b);
! 550: }
! 551: }
! 552: if (0) {
! 553: int i;
! 554: short r, g, b;
! 555: for (i = 0; i < 8; i++) {
! 556: color_content(i, &r, &g, &b);
! 557: palette[i].r = r * .001;
! 558: palette[i].g = g * .001;
! 559: palette[i].b = b * .001;
! 560: }
! 561: }
! 562:
! 563:
! 564: if (colormode == coerce_256) {
! 565: buffer_render_256();
! 566: }
! 567:
! 568: refresh();
! 569: }
! 570:
! 571: static void ensure_size( );
! 572:
! 573: static int term_getkey( ) {
! 574: Term.mouse.justPressed = 0;
! 575: Term.mouse.justReleased = 0;
! 576: Term.mouse.justMoved = 0;
! 577:
! 578: while (1) {
! 579: int got = getch();
! 580: if (got == KEY_RESIZE) {
! 581: ensure_size( );
! 582: } else if (got == KEY_MOUSE) {
! 583: MEVENT mevent;
! 584: getmouse (&mevent);
! 585: Term.mouse.x = mevent.x;
! 586: Term.mouse.y = mevent.y;
! 587: Term.mouse.shift = (mevent.bstate & BUTTON_SHIFT) != 0;
! 588: Term.mouse.control = (mevent.bstate & BUTTON_CTRL) != 0;
! 589: if (mevent.bstate & BUTTON1_PRESSED) {
! 590: Term.mouse.justPressed = 1;
! 591: Term.mouse.isPressed = 1;
! 592: } else if (mevent.bstate & BUTTON1_RELEASED) {
! 593: if (Term.mouse.isPressed) {
! 594: Term.mouse.justReleased = 1;
! 595: Term.mouse.isPressed = 0;
! 596: }
! 597: } else {
! 598: Term.mouse.justMoved = 1;
! 599: }
! 600: return TERM_MOUSE;
! 601: } else {
! 602: if (got == KEY_ENTER) got = 13; // KEY_ENTER -> ^M for systems with odd values for KEY_ENTER
! 603: if (got == ERR) return TERM_NONE;
! 604: else return got;
! 605: }
! 606: }
! 607: }
! 608:
! 609: static int term_has_key() {
! 610: int ch = getch();
! 611: if (ch != ERR) {
! 612: ungetch(ch);
! 613: return 1;
! 614: } else {
! 615: return 0;
! 616: }
! 617: }
! 618:
! 619: static void ensure_size( ) {
! 620: int w = minsize.width, h = minsize.height;
! 621:
! 622: getmaxyx(stdscr, Term.height, Term.width);
! 623: if (Term.height < h || Term.width < w) {
! 624: getmaxyx(stdscr, Term.height, Term.width);
! 625: nodelay(stdscr, FALSE);
! 626: while (Term.height < h || Term.width < w) {
! 627: erase();
! 628: attrset(COLOR_ATTR(7));
! 629:
! 630: mvprintw(1,0,"Brogue needs a terminal window that is at least [%d x %d]", w, h);
! 631:
! 632: attrset(COLOR_ATTR(15));
! 633: mvprintw(2,0,"If your terminal can be resized, resize it now.\n");
! 634:
! 635: attrset(COLOR_ATTR(7));
! 636: mvprintw(3,0,"Press ctrl-c at any time to quit.\n");
! 637:
! 638: printw("Width: %d/%d\n", Term.width, w);
! 639: printw("Height: %d/%d\n", Term.height, h);
! 640:
! 641: mvprintw(10, 0, "Colors (pairs): %d (%d)\n", COLORS, COLOR_PAIRS);
! 642:
! 643: getch();
! 644: getmaxyx(stdscr, Term.height, Term.width);
! 645: }
! 646: nodelay(stdscr, TRUE);
! 647: erase();
! 648: refresh();
! 649: }
! 650: }
! 651:
! 652: static void term_resize(int w, int h) {
! 653: minsize.width = w;
! 654: minsize.height = h;
! 655:
! 656: // try to set the terminal size if the terminal will let us:
! 657: term_set_size(h, w);
! 658: // (this works in gnome-terminal, but causes trouble for curses on maximized windows.)
! 659:
! 660: // now make sure it worked, and ask the user to resize the terminal if it didn't
! 661: ensure_size();
! 662:
! 663:
! 664: // make a new cell buffer
! 665:
! 666: if (cell_buffer) free(cell_buffer);
! 667: cell_buffer = malloc(sizeof(pairmode_cell) * w * h);
! 668: // add error checking
! 669: int i;
! 670:
! 671: for (i = 0; i < w * h; i++) {
! 672: // I guess we could just zero it all, hmm
! 673: cell_buffer[i].ch = 0;
! 674: cell_buffer[i].pair = 0;
! 675: cell_buffer[i].fore.idx = 0;
! 676: cell_buffer[i].back.idx = 0;
! 677: }
! 678: }
! 679:
! 680: static void term_wait(int ms) {
! 681: napms(ms);
! 682: }
! 683:
! 684:
! 685: struct {
! 686: char *name;
! 687: int ch;
! 688: } curses_keys[] = {
! 689: {"NONE", TERM_NONE},
! 690:
! 691: {"TAB", '\t'},
! 692: {"ENTER", '\n'},
! 693: {"RETURN", '\n'},
! 694: {"SPACE", ' '},
! 695:
! 696: {"ESC", 27},
! 697: {"ESCAPE", 27},
! 698:
! 699: {"BREAK", KEY_BREAK},
! 700: {"SRESET", KEY_SRESET},
! 701: {"RESET", KEY_RESET},
! 702: {"DOWN", KEY_DOWN},
! 703: {"UP", KEY_UP },
! 704: {"LEFT", KEY_LEFT},
! 705: {"RIGHT", KEY_RIGHT},
! 706: {"HOME", KEY_HOME},
! 707: {"BACKSPACE", KEY_BACKSPACE},
! 708: {"F1", KEY_F(1)},
! 709: {"F2", KEY_F(2)},
! 710: {"F3", KEY_F(3)},
! 711: {"F4", KEY_F(4)},
! 712: {"F5", KEY_F(5)},
! 713: {"F6", KEY_F(6)},
! 714: {"F7", KEY_F(7)},
! 715: {"F8", KEY_F(8)},
! 716: {"F9", KEY_F(9)},
! 717: {"F10", KEY_F(10)},
! 718: {"F11", KEY_F(11)},
! 719: {"F12", KEY_F(12)},
! 720: {"DL", KEY_DL},
! 721: {"IL", KEY_IL},
! 722: {"DC", KEY_DC},
! 723: {"DEL", KEY_DC},
! 724: {"DELETE", KEY_DC},
! 725: {"IC", KEY_IC},
! 726: {"EIC", KEY_EIC},
! 727: {"CLEAR", KEY_CLEAR},
! 728: {"EOS", KEY_EOS},
! 729: {"EOL", KEY_EOL},
! 730: {"SF", KEY_SF},
! 731: {"SR", KEY_SR},
! 732:
! 733: {"PGUP", KEY_NPAGE},
! 734: {"PGDN", KEY_PPAGE},
! 735: {"PAGEDOWN", KEY_NPAGE},
! 736: {"PAGEUP", KEY_PPAGE},
! 737: {"NPAGE", KEY_NPAGE},
! 738: {"PPAGE", KEY_PPAGE},
! 739:
! 740: {"STAB", KEY_STAB},
! 741: {"CTAB", KEY_CTAB},
! 742: {"CATAB", KEY_CATAB},
! 743:
! 744: {"PRINT", KEY_PRINT},
! 745: {"LL", KEY_LL},
! 746: {"A1", KEY_A1},
! 747: {"A3", KEY_A3},
! 748: {"B2", KEY_B2},
! 749: {"C1", KEY_C1},
! 750: {"C3", KEY_C3},
! 751: {"BTAB", KEY_BTAB},
! 752: {"BEG", KEY_BEG },
! 753: {"CANCEL", KEY_CANCEL},
! 754: {"CLOSE", KEY_CLOSE},
! 755: {"COMMAND", KEY_COMMAND},
! 756: {"COPY", KEY_COPY},
! 757: {"CREATE", KEY_CREATE},
! 758: {"END", KEY_END },
! 759: {"EXIT", KEY_EXIT},
! 760: {"FIND", KEY_FIND},
! 761: {"HELP", KEY_HELP},
! 762: {"MARK", KEY_MARK},
! 763: {"MESSAGE", KEY_MESSAGE},
! 764: {"MOVE", KEY_MOVE},
! 765: {"NEXT", KEY_NEXT},
! 766: {"OPEN", KEY_OPEN},
! 767: {"OPTIONS", KEY_OPTIONS},
! 768: {"PREVIOUS", KEY_PREVIOUS},
! 769: {"REDO", KEY_REDO},
! 770: {"REFERENCE", KEY_REFERENCE},
! 771: {"REFRESH", KEY_REFRESH},
! 772: {"REPLACE", KEY_REPLACE},
! 773: {"RESTART", KEY_RESTART},
! 774: {"RESUME", KEY_RESUME},
! 775: {"SAVE", KEY_SAVE},
! 776: {"SBEG", KEY_SBEG},
! 777: {"SCANCEL", KEY_SCANCEL},
! 778: {"SCOMMAND", KEY_SCOMMAND},
! 779: {"SCOPY", KEY_SCOPY},
! 780: {"SCREATE", KEY_SCREATE},
! 781: {"SDC", KEY_SDC },
! 782: {"SDL", KEY_SDL },
! 783: {"SELECT", KEY_SELECT},
! 784: {"SEND", KEY_SEND},
! 785: {"SEOL", KEY_SEOL},
! 786: {"SEXIT", KEY_SEXIT},
! 787: {"SFIND", KEY_SFIND},
! 788: {"SHELP", KEY_SHELP},
! 789: {"SHOME", KEY_SHOME},
! 790: {"SIC", KEY_SIC },
! 791: {"SLEFT", KEY_SLEFT},
! 792: {"SMESSAGE", KEY_SMESSAGE},
! 793: {"SMOVE", KEY_SMOVE},
! 794: {"SNEXT", KEY_SNEXT},
! 795: {"SOPTIONS", KEY_SOPTIONS},
! 796: {"SPREVIOUS", KEY_SPREVIOUS},
! 797: {"SPRINT", KEY_SPRINT},
! 798: {"SREDO", KEY_SREDO},
! 799: {"SREPLACE", KEY_SREPLACE},
! 800: {"SRIGHT", KEY_SRIGHT},
! 801: {"SRSUME", KEY_SRSUME},
! 802: {"SSAVE", KEY_SSAVE},
! 803: {"SSUSPEND", KEY_SSUSPEND},
! 804: {"SUNDO", KEY_SUNDO},
! 805: {"SUSPEND", KEY_SUSPEND},
! 806: {"UNDO", KEY_UNDO},
! 807: {"MOUSE", KEY_MOUSE},
! 808: {"RESIZE", KEY_RESIZE},
! 809: {NULL, 0},
! 810: };
! 811:
! 812: int term_keycodeByName(const char *name) {
! 813: int i = 0;
! 814: while (curses_keys[i].name != NULL) {
! 815: if (strcmp(name, curses_keys[i].name) == 0) {
! 816: return curses_keys[i].ch;
! 817: }
! 818: i++;
! 819: }
! 820:
! 821: return name[0];
! 822: }
! 823:
! 824:
! 825: struct term_t Term = {
! 826: term_start,
! 827: term_end,
! 828: term_mvaddch,
! 829: term_refresh,
! 830: term_getkey,
! 831: term_wait,
! 832: term_has_key,
! 833: term_title,
! 834: term_resize,
! 835: term_keycodeByName,
! 836: {KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_BACKSPACE, KEY_DC, KEY_F(12)}
! 837: };
CVSweb