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