Home | History | Annotate | Line # | Download | only in dist
colour.c revision 1.2
      1 /* $Id: colour.c,v 1.2 2011/08/22 06:52:35 he Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2008 Nicholas Marriott <nicm (at) users.sourceforge.net>
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  */
     18 
     19 #include <sys/types.h>
     20 
     21 #include <ctype.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 
     25 #include "tmux.h"
     26 
     27 /*
     28  * Colour to string conversion functions. Bit 8 of the colour means it is one
     29  * of the 256 colour palette.
     30  */
     31 
     32 /* An RGB colour. */
     33 struct colour_rgb {
     34 	u_char	r;
     35 	u_char	g;
     36 	u_char	b;
     37 };
     38 
     39 /* 256 colour RGB table, generated on first use. */
     40 struct colour_rgb *colour_rgb_256;
     41 
     42 void	colour_rgb_generate256(void);
     43 u_int	colour_rgb_distance(struct colour_rgb *, struct colour_rgb *);
     44 int	colour_rgb_find(struct colour_rgb *);
     45 
     46 /* Generate 256 colour RGB table. */
     47 void
     48 colour_rgb_generate256(void)
     49 {
     50 	struct colour_rgb	*rgb;
     51 	u_int			 i, r, g, b;
     52 
     53 	/*
     54 	 * Allocate the table. The first 16 colours are often changed by users
     55 	 * and terminals so don't include them.
     56 	 */
     57 	colour_rgb_256 = xcalloc(240, sizeof *colour_rgb_256);
     58 
     59 	/* Add the colours first. */
     60 	r = g = b = 0;
     61 	for (i = 240; i > 24; i--) {
     62 		rgb = &colour_rgb_256[240 - i];
     63 
     64 		if (r != 0)
     65 			rgb->r = (r * 40) + 55;
     66 		if (g != 0)
     67 			rgb->g = (g * 40) + 55;
     68 		if (b != 0)
     69 			rgb->b = (b * 40) + 55;
     70 
     71 		b++;
     72 		if (b > 5) {
     73 			b = 0;
     74 			g++;
     75 		}
     76 		if (g > 5) {
     77 			g = 0;
     78 			r++;
     79 		}
     80 	}
     81 
     82 	/* Then add the greys. */
     83 	for (i = 24; i > 0; i--) {
     84 		rgb = &colour_rgb_256[240 - i];
     85 
     86 		rgb->r = 8 + (24 - i) * 10;
     87 		rgb->g = 8 + (24 - i) * 10;
     88 		rgb->b = 8 + (24 - i) * 10;
     89 	}
     90 }
     91 
     92 /* Get a measure of colour RGB distance. */
     93 u_int
     94 colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2)
     95 {
     96 	int	r, g, b;
     97 
     98 	r = rgb1->r - rgb2->r;
     99 	g = rgb1->g - rgb2->g;
    100 	b = rgb1->b - rgb2->b;
    101 	return (r * r + g * g + b * b);
    102 }
    103 
    104 /* Work out the nearest colour from the 256 colour set. */
    105 int
    106 colour_rgb_find(struct colour_rgb *rgb)
    107 {
    108 	u_int	distance, lowest;
    109 	u_int	colour, i;
    110 
    111 	if (colour_rgb_256 == NULL)
    112 		colour_rgb_generate256();
    113 
    114 	colour = 16;
    115 	lowest = UINT_MAX;
    116 	for (i = 1; i < 240; i++) {
    117 		distance = colour_rgb_distance(&colour_rgb_256[i], rgb);
    118 		if (distance < lowest) {
    119 			lowest = distance;
    120 			colour = 16 + i;
    121 		}
    122 	}
    123 	return (colour);
    124 }
    125 
    126 /* Set grid cell foreground colour. */
    127 void
    128 colour_set_fg(struct grid_cell *gc, int c)
    129 {
    130 	if (c & 0x100)
    131 		gc->flags |= GRID_FLAG_FG256;
    132 	gc->fg = c;
    133 }
    134 
    135 /* Set grid cell background colour. */
    136 void
    137 colour_set_bg(struct grid_cell *gc, int c)
    138 {
    139 	if (c & 0x100)
    140 		gc->flags |= GRID_FLAG_BG256;
    141 	gc->bg = c;
    142 }
    143 
    144 /* Convert colour to a string. */
    145 const char *
    146 colour_tostring(int c)
    147 {
    148 	static char	s[32];
    149 
    150 	if (c & 0x100) {
    151 		xsnprintf(s, sizeof s, "colour%u", c & ~0x100);
    152 		return (s);
    153 	}
    154 
    155 	switch (c) {
    156 	case 0:
    157 		return ("black");
    158 	case 1:
    159 		return ("red");
    160 	case 2:
    161 		return ("green");
    162 	case 3:
    163 		return ("yellow");
    164 	case 4:
    165 		return ("blue");
    166 	case 5:
    167 		return ("magenta");
    168 	case 6:
    169 		return ("cyan");
    170 	case 7:
    171 		return ("white");
    172 	case 8:
    173 		return ("default");
    174 	}
    175 	return (NULL);
    176 }
    177 
    178 /* Convert colour from string. */
    179 int
    180 colour_fromstring(const char *s)
    181 {
    182 	const char		*errstr;
    183 	const char		*cp;
    184 	struct colour_rgb	 rgb;
    185 	int			 n;
    186 
    187 	if (*s == '#' && strlen(s) == 7) {
    188 		for (cp = s + 1; isxdigit((u_char) *cp); cp++)
    189 			;
    190 		if (*cp != '\0')
    191 			return (-1);
    192 		n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &rgb.r, &rgb.g, &rgb.b);
    193 		if (n != 3)
    194 			return (-1);
    195 		return (colour_rgb_find(&rgb) | 0x100);
    196 	}
    197 
    198 	if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) {
    199 		n = strtonum(s + (sizeof "colour") - 1, 0, 255, &errstr);
    200 		if (errstr != NULL)
    201 			return (-1);
    202 		return (n | 0x100);
    203 	}
    204 
    205 	if (strcasecmp(s, "black") == 0 || (s[0] == '0' && s[1] == '\0'))
    206 		return (0);
    207 	if (strcasecmp(s, "red") == 0 || (s[0] == '1' && s[1] == '\0'))
    208 		return (1);
    209 	if (strcasecmp(s, "green") == 0 || (s[0] == '2' && s[1] == '\0'))
    210 		return (2);
    211 	if (strcasecmp(s, "yellow") == 0 || (s[0] == '3' && s[1] == '\0'))
    212 		return (3);
    213 	if (strcasecmp(s, "blue") == 0 || (s[0] == '4' && s[1] == '\0'))
    214 		return (4);
    215 	if (strcasecmp(s, "magenta") == 0 || (s[0] == '5' && s[1] == '\0'))
    216 		return (5);
    217 	if (strcasecmp(s, "cyan") == 0 || (s[0] == '6' && s[1] == '\0'))
    218 		return (6);
    219 	if (strcasecmp(s, "white") == 0 || (s[0] == '7' && s[1] == '\0'))
    220 		return (7);
    221 	if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0'))
    222 		return (8);
    223 	return (-1);
    224 }
    225 
    226 /* Convert 256 colour palette to 16. */
    227 u_char
    228 colour_256to16(u_char c)
    229 {
    230 	static const u_char table[256] = {
    231 		 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
    232 		 0,  4,  4,  4, 12, 12,  2,  6,  4,  4, 12, 12,  2,  2,  6,  4,
    233 		12, 12,  2,  2,  2,  6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10,
    234 		10, 10, 10, 14,  1,  5,  4,  4, 12, 12,  3,  8,  4,  4, 12, 12,
    235 		 2,  2,  6,  4, 12, 12,  2,  2,  2,  6, 12, 12, 10, 10, 10, 10,
    236 		14, 12, 10, 10, 10, 10, 10, 14,  1,  1,  5,  4, 12, 12,  1,  1,
    237 		 5,  4, 12, 12,  3,  3,  8,  4, 12, 12,  2,  2,  2,  6, 12, 12,
    238 		10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14,  1,  1,  1,  5,
    239 		12, 12,  1,  1,  1,  5, 12, 12,  1,  1,  1,  5, 12, 12,  3,  3,
    240 		 3,  7, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14,
    241 		 9,  9,  9,  9, 13, 12,  9,  9,  9,  9, 13, 12,  9,  9,  9,  9,
    242 		13, 12,  9,  9,  9,  9, 13, 12, 11, 11, 11, 11,  7, 12, 10, 10,
    243 		10, 10, 10, 14,  9,  9,  9,  9,  9, 13,  9,  9,  9,  9,  9, 13,
    244 		 9,  9,  9,  9,  9, 13,  9,  9,  9,  9,  9, 13,  9,  9,  9,  9,
    245 		 9, 13, 11, 11, 11, 11, 11, 15,  0,  0,  0,  0,  0,  0,  8,  8,
    246 		 8,  8,  8,  8,  7,  7,  7,  7,  7,  7, 15, 15, 15, 15, 15, 15
    247 	};
    248 
    249 	return (table[c]);
    250 }
    251 
    252 /* Convert 256 colour palette to 88. */
    253 u_char
    254 colour_256to88(u_char c)
    255 {
    256 	static const u_char table[256] = {
    257 		 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
    258 		16, 17, 17, 18, 18, 19, 20, 21, 21, 22, 22, 23, 20, 21, 21, 22,
    259 		22, 23, 24, 25, 25, 26, 26, 27, 24, 25, 25, 26, 26, 27, 28, 29,
    260 		29, 30, 30, 31, 32, 33, 33, 34, 34, 35, 36, 37, 37, 38, 38, 39,
    261 		36, 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 43, 40, 41, 41, 42,
    262 		42, 43, 44, 45, 45, 46, 46, 47, 32, 33, 33, 34, 34, 35, 36, 37,
    263 		37, 38, 38, 39, 36, 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 43,
    264 		40, 41, 41, 42, 42, 43, 44, 45, 45, 46, 46, 47, 48, 49, 49, 50,
    265 		50, 51, 52, 53, 53, 54, 54, 55, 52, 53, 53, 54, 54, 55, 56, 57,
    266 		57, 58, 58, 59, 56, 57, 57, 58, 58, 59, 60, 61, 61, 62, 62, 63,
    267 		48, 49, 49, 50, 50, 51, 52, 53, 53, 54, 54, 55, 52, 53, 53, 54,
    268 		54, 55, 56, 57, 57, 58, 58, 59, 56, 57, 57, 58, 58, 59, 60, 61,
    269 		61, 62, 62, 63, 64, 65, 65, 66, 66, 67, 68, 69, 69, 70, 70, 71,
    270 		68, 69, 69, 70, 70, 71, 72, 73, 73, 74, 74, 75, 72, 73, 73, 74,
    271 		74, 75, 76, 77, 77, 78, 78, 79,  0,  0, 80, 80, 80, 81, 81, 81,
    272 		82, 82, 82, 83, 83, 83, 84, 84, 84, 85, 85, 85, 86, 86, 86, 87
    273 	};
    274 
    275 	return (table[c]);
    276 }
    277