xref: /minix3/external/bsd/tmux/dist/colour.c (revision b80da2a01d0bb632707b7b4e974aa32eaebbcc6f)
1 /* $Id: colour.c,v 1.3 2011/08/22 09:19:51 he Exp $ */
2 
3 /*
4  * Copyright (c) 2008 Nicholas Marriott <nicm@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 = 0; 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