Logo Search packages:      
Sourcecode: ncurses version File versions

color.c

/*
** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
**
** This file is part of TACK.
**
** TACK is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2, or (at your option)
** any later version.
**
** TACK is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with TACK; see the file COPYING.  If not, write to
** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA 02111-1307, USA.
*/

#include <tack.h>

MODULE_ID("$Id: color.c,v 1.5 2004/01/16 23:14:25 Jochen.Voss Exp $")

/*
 * Color terminal tests.  Has only one entry point: test_color().
 */

static void color_check(struct test_list *, int *, int *);
static void color_setf(struct test_list *, int *, int *);
static void color_matrix(struct test_list *, int *, int *);
static void color_ncv(struct test_list *, int *, int *);
static void color_ccc(struct test_list *, int *, int *);
static void color_bce(struct test_list *, int *, int *);

struct test_list color_test_list[] = {
      {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
      {MENU_NEXT, 2, "colors) (pairs", 0, 0, color_check, 0},
      {MENU_NEXT, 12, "setf) (setb) (scp", 0, 0, color_setf, 0},
      {MENU_NEXT, 24, "op", 0, 0, color_matrix, 0},
      {MENU_NEXT, 16, "ncv", 0, 0, color_ncv, 0},
      {MENU_NEXT, 0, "bce", 0, 0, color_bce, 0},
      {MENU_NEXT | MENU_CLEAR, 0, "ccc) (initc) (initp", "hls op oc", 0, color_ccc, 0},
      {MENU_LAST, 0, 0, 0, 0, 0, 0}
};

#ifndef COLOR_BLACK
#define COLOR_BLACK     0
#define COLOR_BLUE      1
#define COLOR_GREEN     2
#define COLOR_CYAN      3
#define COLOR_RED       4
#define COLOR_MAGENTA   5
#define COLOR_YELLOW    6
#define COLOR_WHITE     7
#endif

struct color_table {
      const char *name;
      int index;
      int r, g, b;
      int h, l, s;
};

static struct color_table def_colors[8] = {
      {"black  ", COLOR_BLACK, 0, 0, 0, 0, 0, 0},
      {"blue   ", COLOR_BLUE, 0, 0, 1000, 330, 50, 100},
      {"green  ", COLOR_GREEN, 0, 1000, 0, 240, 50, 100},
      {"cyan   ", COLOR_CYAN, 0, 1000, 1000, 300, 50, 100},
      {"red    ", COLOR_RED, 1000, 0, 0, 120, 50, 100},
      {"magenta", COLOR_MAGENTA, 1000, 0, 1000, 60, 50, 100},
      {"yellow ", COLOR_YELLOW, 1000, 1000, 0, 180, 50, 100},
      {"white  ", COLOR_WHITE, 1000, 1000, 1000, 0, 100, 0}
};

#define MAX_PAIR  256
static int fg_color[MAX_PAIR] = {COLOR_BLACK, COLOR_BLUE, COLOR_GREEN,
COLOR_CYAN, COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE};
static int bg_color[MAX_PAIR] = {COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK};
static int pairs_used = 8;
static int a_bright_color, bright_value;
static int cookie_monster, color_step, colors_per_line;
static int R, G, B;

static void reset_colors(void)
{
      tc_putp(orig_colors);
      tc_putp(tparm(orig_pair));
}

static int
color_trans(int c)
{                       /* translate or load the color */
      int i;

      for (i = 0; i < pairs_used; i++) {
            if (fg_color[i] == c) {
                  return i;
            }
      }
      if (!can_change) {
            return 0;
      }
      if (pairs_used > max_colors || pairs_used >= MAX_PAIR) {
            pairs_used = 0;
            ptextln("Ran out of colors");
      }
      fg_color[pairs_used] = c;
      bg_color[pairs_used] = c;
      if (hue_lightness_saturation) {
            tc_putp(tparm(initialize_color, pairs_used,
                  def_colors[c].h, def_colors[c].l, def_colors[c].s));
      } else {
            tc_putp(tparm(initialize_color, pairs_used,
                  def_colors[c].r, def_colors[c].g, def_colors[c].b));
      }
      return pairs_used++;
}

static void
new_color(
      int fg,
      int bg,
      int hungry)
{                       /* change the color to fg and bg. */
      int i;

      if (hungry) {
            eat_cookie();
      }
      if (set_a_foreground) {
            /* set ANSI color (setaf) (setab) */
            tc_putp(tparm(set_a_foreground, fg));
            tc_putp(tparm(set_a_background, bg));
      } else if (set_foreground) {
            /* make sure black is zero */
            (void) color_trans(COLOR_BLACK);
            tc_putp(tparm(set_foreground, color_trans(fg)));
            tc_putp(tparm(set_background, color_trans(bg)));
      } else {    /* set color pair */
            for (i = 0; i < pairs_used; i++) {
                  if (fg_color[i] == fg && bg_color[i] == bg) {
                        tc_putp(tparm(set_color_pair, i));
                        if (hungry) {
                              eat_cookie();
                        }
                        return;
                  }
            }
            if (!can_change) {
                  /* try to set just the foreground */
                  for (i = pairs_used - 1; i; i--) {
                        if (fg_color[i] == fg)
                              break;
                  }
                  tc_putp(tparm(set_color_pair, i));
                  if (hungry) {
                        eat_cookie();
                  }
                  return;
            }
            if (pairs_used > max_pairs || pairs_used >= MAX_PAIR) {
                  pairs_used = 0;
                  ptextln("Ran out of color pairs");
            }
            fg_color[pairs_used] = fg;
            bg_color[pairs_used] = bg;
            if (hue_lightness_saturation) {
                  tc_putp(tparm(initialize_pair, pairs_used,
                        def_colors[fg].h, def_colors[fg].l, def_colors[fg].s,
                        def_colors[bg].h, def_colors[bg].l, def_colors[bg].s));
            } else {
                  tc_putp(tparm(initialize_pair, pairs_used,
                        def_colors[fg].r, def_colors[fg].g, def_colors[fg].b,
                        def_colors[bg].r, def_colors[bg].g, def_colors[bg].b));
            }
            tc_putp(tparm(set_color_pair, pairs_used));
            pairs_used++;
      }
      if (hungry) {
            eat_cookie();
      }
}


static void
set_color_step(void)
{                       /* set the color_step for the (ccc) display */
      int i;

      for (i = 2; i < 1000; i++) {
            if ((i * i * i) >= max_colors) {
                  break;
            }
      }
      color_step = 1000 / (i - 1);
}


static void
rgb_2_hls(int r, int g, int b, int *h, int *l, int *s)
{                       /* convert RGB to HLS system */
      int min, max, t;

      if ((min = g < r ? g : r) > b) {
            min = b;
      }
      if ((max = g > r ? g : r) < b) {
            max = b;
      }

      /* calculate lightness */
      *l = (min + max) / 20;

      if (min == max) { /* black, white and all shades of gray */
            *h = 0;
            *s = 0;
            return;
      }
      /* calculate saturation */
      if (*l < 50) {
            *s = ((max - min) * 100) / (max + min);
      } else {
            *s = ((max - min) * 100) / (2000 - max - min);
      }

      /* calculate hue */
      if (r == max) {
            t = 120 + ((g - b) * 60) / (max - min);
      } else if (g == max) {
            t = 240 + ((b - r) * 60) / (max - min);
      } else {
            t = 360 + ((r - g) * 60) / (max - min);
      }
      *h = t % 360;
}


static void
send_color(int p, int r, int g, int b)
{                       /* send the initialize_color (initc) command */
      int h, l, s;

      if (hue_lightness_saturation) {
            rgb_2_hls(r, g, b, &h, &l, &s);
            tc_putp(tparm(initialize_color, p, h, l, s));
      } else {
            tc_putp(tparm(initialize_color, p, r, g, b));
      }
}


static void
send_pair(int p, int fr, int fg, int fb, int br, int bg, int bb)
{                       /* send the initialize_pair (initp) command */
      int fh, fl, fs, bh, bl, bs;

      if (hue_lightness_saturation) {
            rgb_2_hls(fr, fg, fb, &fh, &fl, &fs);
            rgb_2_hls(br, bg, bb, &bh, &bl, &bs);
            tc_putp(tparm(initialize_pair, p, fh, fl, fs, bh, bl, bs));
      } else {
            tc_putp(tparm(initialize_pair, p, fr, fg, fb, bb, bg, bb));
      }
}


static int
load_palette(int n)
{                       /* load the color palette */
      int rgb;

      for (;;) {
            if (pairs_used >= n) {
                  return FALSE;
            }
            if (set_a_foreground || set_foreground) {
                  if (pairs_used >= max_colors) {
                        return FALSE;
                  }
                  send_color(pairs_used, R, G, B);
                  rgb = R + G + B;
                  if (rgb > bright_value) {
                        bright_value = rgb;
                        a_bright_color = pairs_used;
                  }
            } else {
                  if (pairs_used >= max_pairs) {
                        return FALSE;
                  }
                  if (pairs_used == 0) {
                        send_pair(pairs_used, 1000, 1000, 1000, R, G, B);
                  } else {
                        send_pair(pairs_used, R, G, B, R, G, B);
                  }
            }
            pairs_used++;
            if ((B += color_step) > 1000) {
                  B = 0;
                  if ((G += color_step) > 1000) {
                        G = 0;
                        if ((R += color_step) > 1000) {
                              return TRUE;
                        }
                  }
            }
      }
}


static int
rainbow(int n)
{                       /* print the programmable color display */
      int i, c, d, palette_full, initial_pair;
      static const struct {
            const char *name;
            char ch;
      }  splat[] = {
            {"Bg normal", ' '},
            {"Fg normal", ' '},
            {0, 0}
      };

      if ((set_a_foreground || set_foreground)
        ? pairs_used >= max_colors
        : pairs_used >= max_pairs) {
            ptext("New palette: ");
            (void) wait_here();
            initial_pair = pairs_used = 1;
            bright_value = 0;
      } else if (line_count + 3 >= lines) {
            ptext("Go: ");
            (void) wait_here();
            put_clear();
            initial_pair = pairs_used = 1;
            bright_value = 0;
            n++;
      } else {
            initial_pair = pairs_used;
            n += initial_pair;
      }
      palette_full = load_palette(n);
      for (d = 0; splat[d].name; d++) {
            c = splat[d].ch;
            if (d == 1) {
                  put_mode(enter_reverse_mode);
            }
            for (i = initial_pair; i < n; i++) {
                  if (i >= pairs_used) {
                        break;
                  }
                  if (set_a_foreground) {
                        if (i >= max_colors) {
                              break;
                        }
                        tc_putp(tparm(set_a_foreground, i));
                        tc_putp(tparm(set_a_background, i));
                  } else if (set_foreground) {
                        if (i >= max_colors) {
                              break;
                        }
                        tc_putp(tparm(set_foreground, i));
                        tc_putp(tparm(set_background, i));
                  } else {
                        if (i >= max_pairs) {
                              break;
                        }
                        tc_putp(tparm(set_color_pair, i));
                  }
                  putchp(c);
            }
            if (d == 1) {
                  put_mode(exit_attribute_mode);
            }
            if (set_a_foreground) {
                  tc_putp(tparm(set_a_foreground, a_bright_color));
                  tc_putp(tparm(set_a_background, 0));
            } else if (set_foreground) {
                  tc_putp(tparm(set_foreground, a_bright_color));
                  tc_putp(tparm(set_background, 0));
            } else {
                  tc_putp(tparm(set_color_pair, 0));
            }
            put_str("   ");
            put_str(splat[d].name);
            put_crlf();
      }
      return palette_full;
}


static void
ncv_display(int m)
{                       /* print the no_color_video (ncv) test line */
      putchp('0' + m);
      putchp(' ');
      eat_cookie();
      set_attr(1 << m);
      sprintf(temp, "%-11s", alt_modes[m].name);
      put_str(temp);

      new_color(COLOR_BLUE, COLOR_BLACK, TRUE);
      put_str("blue");

      new_color(COLOR_BLACK, COLOR_GREEN, TRUE);
      put_str("green");

      new_color(COLOR_WHITE, COLOR_BLACK, TRUE);
      put_str(alt_modes[m].name);
      eat_cookie();
      set_attr(0);
      reset_colors();
      put_crlf();
}


static void
dump_colors(void)
{                       /* display the colors in some esthetic
                           pattern */
      static int xmap[8] = {0, 3, 4, 7, 1, 2, 5, 6};
      int i, j, k, xi, xj, width, p, cs;
      int found_one;

      cs = color_step <= 125 ? 125 : color_step;
      width = (1000 / cs) + 1;
      for (xi = 0; xi < 16; xi++) {
            i = (xi & 8) ? xi ^ 15 : xi;
            R = i * cs;
            if (R <= 1000) {
                  found_one = FALSE;
                  for (xj = 0; xj < 32; xj++) {
                        j = ((xj & 8) ? xj ^ 15 : xj) & 7;
                        k = xmap[((xi >> 1) & 4) + (xj >> 3)];
                        G = j * cs;
                        B = k * cs;
                        if (G <= 1000 && B <= 1000) {
                              p = (k * width + j) * width + i;
                              if (set_a_background) {
                                    if (p >= max_colors) {
                                          continue;
                                    }
                                    send_color(p, R, G, B);
                                    tc_putp(tparm(set_a_background, p));
                              } else if (set_background) {
                                    if (p >= max_colors) {
                                          continue;
                                    }
                                    send_color(p, R, G, B);
                                    tc_putp(tparm(set_background, p));
                              } else {
                                    if (p >= max_pairs) {
                                          continue;
                                    }
                                    send_pair(p, R, G, B, R, G, B);
                                    tc_putp(tparm(set_color_pair, p));
                              }
                              found_one = TRUE;
                              putchp(' ');
                              putchp(' ');
                        }
                  }
                  if (found_one) {
                        put_crlf();
                  }
            }
      }
}

/*
**    color_check(test_list, status, ch)
**
**    test (colors) and (pairs)
*/
static void
color_check(
      struct test_list *t,
      int *state,
      int *ch)
{
      if (max_colors <= 0 && max_pairs <= 0) {
            ptext("This is not a color terminal; (colors) and (pairs) are missing.  ");
            *state |= MENU_STOP;
      } else {
            sprintf(temp, "This terminal can display %d colors and %d color pairs.  (colors) (pairs)",
                  max_colors, max_pairs);
            ptextln(temp);
      }
      generic_done_message(t, state, ch);
}

/*
**    color_setf(test_list, status, ch)
**
**    test (setf) (setb) and (scp)
*/
static void
color_setf(
      struct test_list *t,
      int *state,
      int *ch)
{
      int i, j;

      if (max_colors <= 0 && max_pairs <= 0) {
            ptext("This is not a color terminal; (colors) and (pairs) are missing.  ");
            generic_done_message(t, state, ch);
            *state |= MENU_STOP;
            return;
      }
      if ((set_a_foreground == NULL || set_a_background == NULL)
       && (set_foreground == NULL   || set_background == NULL)
       && set_color_pair == NULL) {
            ptextln("Both set foreground (setaf/setf) and set color pair (scp) are not present.");
            if (!set_a_background || !set_background) {
                  ptextln("(setab/setb) set background not present");
            }
            ptext("These must be defined for color testing.  ");
            generic_done_message(t, state, ch);
            *state |= MENU_STOP;
            return;
      }
      /* initialize the color palette */
      pairs_used = max_colors >= 8 ? 8 : max_colors;
      reset_colors();
      new_color(COLOR_WHITE, COLOR_BLACK, FALSE);

      ptextln("(setf) (setb) (scp) The following colors are predefined:");
      ptextln("\n   Foreground     Background");
      put_crlf();
      j = max_colors > 8 ? 8 : max_colors;
      /*
       * the black on white test is the same as the white on black test.
       */
      for (i = 1; i < j; i++) {
            putchp('0' + def_colors[i].index);
            putchp(' ');
            sprintf(temp, " %s ", def_colors[i].name);

            new_color(def_colors[i].index, COLOR_BLACK, TRUE);
            put_str(temp);

            new_color(COLOR_BLACK, COLOR_BLACK, TRUE);
            put_str("  ");

            new_color(COLOR_BLACK, def_colors[i].index, TRUE);
            put_str(temp);

            new_color(COLOR_WHITE, COLOR_BLACK, FALSE);
            put_crlf();
      }
      reset_colors();
      put_crlf();
      generic_done_message(t, state, ch);
}

/*
**    color_matrix(test_list, status, ch)
**
**    test (pairs) (op)
*/
static void
color_matrix(
      struct test_list *t,
      int *state,
      int *ch)
{
      int i, j, matrix_size, matrix_area, brightness;

      matrix_size = max_colors > 8 ? 8 : max_colors;

      sprintf(temp, "(pairs) There are %d color pairs.", max_pairs);
      ptextln(temp);

      for ( ; matrix_size; matrix_size--) {
            if (matrix_size * matrix_size <= max_pairs) {
                  break;
            }
      }
      matrix_area = matrix_size * matrix_size;
      for (brightness = 0; brightness < 2; brightness++) {
            put_crlf();
            sprintf(temp,
                  "%dx%d matrix of foreground/background colors, bright *o%s*",
                  matrix_size, matrix_size, brightness ? "n" : "ff");
            put_str(temp);

            put_str("\n          ");
            for (i = 0; i < matrix_size; i++) {
                  (void) sprintf(temp, "%-8s", def_colors[i].name);
                  put_str(temp);
            }
            for (j = 0; j < matrix_area; j++) {
                  if (j % matrix_size == 0) {
                        reset_colors();
                        put_crlf();
                        if (brightness) {
                              tc_putp(exit_attribute_mode);
                        }
                        (void) sprintf(temp, "%-8s", def_colors[j / matrix_size].name);
                        put_str(temp);
                        if (brightness) {
                              put_mode(enter_bold_mode);
                        }
                  }
                  new_color(def_colors[j % matrix_size].index,
                        def_colors[j / matrix_size].index,
                        FALSE);
                  put_str("  Hello ");
            }
            reset_colors();
            if (brightness) {
                  tc_putp(exit_attribute_mode);
            }
            put_crlf();
      }
      generic_done_message(t, state, ch);
}

/*
**    color_ncv(test_list, status, ch)
**
**    test (ncv)
*/
static void
color_ncv(
      struct test_list *t,
      int *state,
      int *ch)
{
      int i;

      if (no_color_video == -1) {
            /* I have no idea what this means */
            return;
      }
      sprintf(temp, "According to no_color_video (ncv) which is %d, the following attributes should work correctly with color.", no_color_video);
      ptextln(temp);
      put_crlf();
      set_attr(0);
      ncv_display(0);
      for (i = 1; i <= 9; i++) {
            if (((no_color_video >> (mode_map[i] - 1)) & 1) == 0) {
                  ncv_display(mode_map[i]);
            }
      }
      if (no_color_video & 0x3ff) {
            ptextln("\nThe following attributes should not work correctly with color. (ncv)\n");
            for (i = 1; i <= 9; i++) {
                  if ((no_color_video >> (mode_map[i] - 1)) & 1) {
                        ncv_display(mode_map[i]);
                  }
            }
      }
      reset_colors();
      put_crlf();
      generic_done_message(t, state, ch);
}

/*
**    color_bce(test_list, status, ch)
**
**    test (bce) background color erase
*/
static void
color_bce(
      struct test_list *t,
      int *state,
      int *ch)
{
      new_color(COLOR_CYAN, COLOR_BLUE, FALSE);
      put_clear();
      put_newlines(2);
      reset_colors();
      ptextln("If the two lines above are blue then back_color_erase (bce) should be true.");
      sprintf(temp, "(bce) is %s in the data base.", back_color_erase ? "true" : "false");
      ptextln(temp);
      generic_done_message(t, state, ch);
}

/*
**    color_ccc(test_list, status, ch)
**
**    test (ccc) color palette test (oc) (op) (initc) (initp)
*/
static void
color_ccc(
      struct test_list *t,
      int *state,
      int *ch)
{
      int i, j;

      if (!can_change) {
            ptextln("Terminal can not change colors (ccc)");
            generic_done_message(t, state, ch);
            return;
      }
      reset_colors();
      pairs_used = 0;
      new_color(COLOR_WHITE, COLOR_BLACK, FALSE);
      sprintf(temp, "Reloading colors (init%c) using %s method",
            set_foreground ? 'c' : 'p',
            hue_lightness_saturation ? "HLS" : "RGB");
      ptextln(temp);
      put_crlf();
      j = max_colors > 7 ? 7 : max_colors;
      /* redisplay the above test with reinitialized colors */
      /* If these colors don't look right to you... */
      for (i = 0; i < j; i++) {
            sprintf(temp, " %s ", def_colors[i ^ 7].name);

            new_color(i ^ 7, COLOR_BLACK, TRUE);
            put_str(temp);

            new_color(COLOR_BLACK, COLOR_BLACK, TRUE);
            put_str("  ");

            new_color(COLOR_BLACK, i ^ 7, TRUE);
            put_str(temp);

            new_color(COLOR_WHITE, COLOR_BLACK, FALSE);
            put_crlf();
      }
      generic_done_message(t, state, ch);
      if (*ch != 0 && *ch != 'n') {
            reset_colors();
            return;
      }

      pairs_used = 0;
      cookie_monster = 0;
      if (magic_cookie_glitch > 0) {
            cookie_monster =
                  ((set_a_foreground || set_foreground)
                        ? magic_cookie_glitch : 0) +
                  ((set_a_background || set_background)
                        ? magic_cookie_glitch : 0) +
                  (set_color_pair ? magic_cookie_glitch : 0);
      }
      set_color_step();
      colors_per_line = max_colors > max_pairs
            ? max_pairs : max_colors;
      j = (columns - 14) / (cookie_monster + 1);
      if (colors_per_line > j) {
            colors_per_line = (j / i) * i;
      }
      sprintf(temp, "RGB color step %d, cookies %d", color_step,
            cookie_monster);
      ptextln(temp);

      R = G = B = 0;
      pairs_used = 0;
      for (;;) {
            if (rainbow(colors_per_line)) {
                  break;
            }
      }
      generic_done_message(t, state, ch);
      if (*ch != 0 && *ch != 'n') {
            reset_colors();
            return;
      }
      dump_colors();
      reset_colors();
      generic_done_message(t, state, ch);
}

Generated by  Doxygen 1.6.0   Back to index