Add window-status-separator option, from Thomas Adam.
[tmux-openbsd.git] / colour.c
blobff492687e59d691483e7867469c656a90c8bb831
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <string.h>
25 #include "tmux.h"
28 * Colour to string conversion functions. Bit 8 of the colour means it is one
29 * of the 256 colour palette.
32 /* An RGB colour. */
33 struct colour_rgb {
34 u_char r;
35 u_char g;
36 u_char b;
39 /* 256 colour RGB table, generated on first use. */
40 struct colour_rgb *colour_rgb_256;
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 *);
46 /* Generate 256 colour RGB table. */
47 void
48 colour_rgb_generate256(void)
50 struct colour_rgb *rgb;
51 u_int i, r, g, b;
54 * Allocate the table. The first 16 colours are often changed by users
55 * and terminals so don't include them.
57 colour_rgb_256 = xcalloc(240, sizeof *colour_rgb_256);
59 /* Add the colours first. */
60 r = g = b = 0;
61 for (i = 240; i > 24; i--) {
62 rgb = &colour_rgb_256[240 - i];
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;
71 b++;
72 if (b > 5) {
73 b = 0;
74 g++;
76 if (g > 5) {
77 g = 0;
78 r++;
82 /* Then add the greys. */
83 for (i = 24; i > 0; i--) {
84 rgb = &colour_rgb_256[240 - i];
86 rgb->r = 8 + (24 - i) * 10;
87 rgb->g = 8 + (24 - i) * 10;
88 rgb->b = 8 + (24 - i) * 10;
92 /* Get colour RGB distance. */
93 u_int
94 colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2)
96 int r, g, b;
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);
104 /* Work out the nearest colour from the 256 colour set. */
106 colour_rgb_find(struct colour_rgb *rgb)
108 u_int distance, lowest, colour, i;
110 if (colour_rgb_256 == NULL)
111 colour_rgb_generate256();
113 colour = 16;
114 lowest = UINT_MAX;
115 for (i = 0; i < 240; i++) {
116 distance = colour_rgb_distance(&colour_rgb_256[i], rgb);
117 if (distance < lowest) {
118 lowest = distance;
119 colour = 16 + i;
122 return (colour);
125 /* Set grid cell foreground colour. */
126 void
127 colour_set_fg(struct grid_cell *gc, int c)
129 if (c & 0x100)
130 gc->flags |= GRID_FLAG_FG256;
131 gc->fg = c;
134 /* Set grid cell background colour. */
135 void
136 colour_set_bg(struct grid_cell *gc, int c)
138 if (c & 0x100)
139 gc->flags |= GRID_FLAG_BG256;
140 gc->bg = c;
143 /* Convert colour to a string. */
144 const char *
145 colour_tostring(int c)
147 static char s[32];
149 if (c & 0x100) {
150 xsnprintf(s, sizeof s, "colour%u", c & ~0x100);
151 return (s);
154 switch (c) {
155 case 0:
156 return ("black");
157 case 1:
158 return ("red");
159 case 2:
160 return ("green");
161 case 3:
162 return ("yellow");
163 case 4:
164 return ("blue");
165 case 5:
166 return ("magenta");
167 case 6:
168 return ("cyan");
169 case 7:
170 return ("white");
171 case 8:
172 return ("default");
173 case 90:
174 return ("brightblack");
175 case 91:
176 return ("brightred");
177 case 92:
178 return ("brightgreen");
179 case 93:
180 return ("brightyellow");
181 case 94:
182 return ("brightblue");
183 case 95:
184 return ("brightmagenta");
185 case 96:
186 return ("brightcyan");
187 case 97:
188 return ("brightwhite");
190 return (NULL);
193 /* Convert colour from string. */
195 colour_fromstring(const char *s)
197 const char *errstr;
198 const char *cp;
199 struct colour_rgb rgb;
200 int n;
202 if (*s == '#' && strlen(s) == 7) {
203 for (cp = s + 1; isxdigit((u_char) *cp); cp++)
205 if (*cp != '\0')
206 return (-1);
207 n = sscanf(s + 1, "%2hhx%2hhx%2hhx", &rgb.r, &rgb.g, &rgb.b);
208 if (n != 3)
209 return (-1);
210 return (colour_rgb_find(&rgb) | 0x100);
213 if (strncasecmp(s, "colour", (sizeof "colour") - 1) == 0) {
214 n = strtonum(s + (sizeof "colour") - 1, 0, 255, &errstr);
215 if (errstr != NULL)
216 return (-1);
217 return (n | 0x100);
220 if (strcasecmp(s, "black") == 0 || (s[0] == '0' && s[1] == '\0'))
221 return (0);
222 if (strcasecmp(s, "red") == 0 || (s[0] == '1' && s[1] == '\0'))
223 return (1);
224 if (strcasecmp(s, "green") == 0 || (s[0] == '2' && s[1] == '\0'))
225 return (2);
226 if (strcasecmp(s, "yellow") == 0 || (s[0] == '3' && s[1] == '\0'))
227 return (3);
228 if (strcasecmp(s, "blue") == 0 || (s[0] == '4' && s[1] == '\0'))
229 return (4);
230 if (strcasecmp(s, "magenta") == 0 || (s[0] == '5' && s[1] == '\0'))
231 return (5);
232 if (strcasecmp(s, "cyan") == 0 || (s[0] == '6' && s[1] == '\0'))
233 return (6);
234 if (strcasecmp(s, "white") == 0 || (s[0] == '7' && s[1] == '\0'))
235 return (7);
236 if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0'))
237 return (8);
238 if (strcasecmp(s, "brightblack") == 0 ||
239 (s[0] == '9' && s[1] == '0' && s[1] == '\0'))
240 return (90);
241 if (strcasecmp(s, "brightred") == 0 ||
242 (s[0] == '9' && s[1] == '1' && s[1] == '\0'))
243 return (91);
244 if (strcasecmp(s, "brightgreen") == 0 ||
245 (s[0] == '9' && s[1] == '2' && s[1] == '\0'))
246 return (92);
247 if (strcasecmp(s, "brightyellow") == 0 ||
248 (s[0] == '9' && s[1] == '3' && s[1] == '\0'))
249 return (93);
250 if (strcasecmp(s, "brightblue") == 0 ||
251 (s[0] == '9' && s[1] == '4' && s[1] == '\0'))
252 return (94);
253 if (strcasecmp(s, "brightmagenta") == 0 ||
254 (s[0] == '9' && s[1] == '5' && s[1] == '\0'))
255 return (95);
256 if (strcasecmp(s, "brightcyan") == 0 ||
257 (s[0] == '9' && s[1] == '6' && s[1] == '\0'))
258 return (96);
259 if (strcasecmp(s, "brightwhite") == 0 ||
260 (s[0] == '9' && s[1] == '7' && s[1] == '\0'))
261 return (97);
262 return (-1);
265 /* Convert 256 colour palette to 16. */
266 u_char
267 colour_256to16(u_char c)
269 static const u_char table[256] = {
270 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
271 0, 4, 4, 4, 12, 12, 2, 6, 4, 4, 12, 12, 2, 2, 6, 4,
272 12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10,
273 10, 10, 10, 14, 1, 5, 4, 4, 12, 12, 3, 8, 4, 4, 12, 12,
274 2, 2, 6, 4, 12, 12, 2, 2, 2, 6, 12, 12, 10, 10, 10, 10,
275 14, 12, 10, 10, 10, 10, 10, 14, 1, 1, 5, 4, 12, 12, 1, 1,
276 5, 4, 12, 12, 3, 3, 8, 4, 12, 12, 2, 2, 2, 6, 12, 12,
277 10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14, 1, 1, 1, 5,
278 12, 12, 1, 1, 1, 5, 12, 12, 1, 1, 1, 5, 12, 12, 3, 3,
279 3, 7, 12, 12, 10, 10, 10, 10, 14, 12, 10, 10, 10, 10, 10, 14,
280 9, 9, 9, 9, 13, 12, 9, 9, 9, 9, 13, 12, 9, 9, 9, 9,
281 13, 12, 9, 9, 9, 9, 13, 12, 11, 11, 11, 11, 7, 12, 10, 10,
282 10, 10, 10, 14, 9, 9, 9, 9, 9, 13, 9, 9, 9, 9, 9, 13,
283 9, 9, 9, 9, 9, 13, 9, 9, 9, 9, 9, 13, 9, 9, 9, 9,
284 9, 13, 11, 11, 11, 11, 11, 15, 0, 0, 0, 0, 0, 0, 8, 8,
285 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15
288 return (table[c]);
291 /* Convert 256 colour palette to 88. */
292 u_char
293 colour_256to88(u_char c)
295 static const u_char table[256] = {
296 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
297 16, 17, 17, 18, 18, 19, 20, 21, 21, 22, 22, 23, 20, 21, 21, 22,
298 22, 23, 24, 25, 25, 26, 26, 27, 24, 25, 25, 26, 26, 27, 28, 29,
299 29, 30, 30, 31, 32, 33, 33, 34, 34, 35, 36, 37, 37, 38, 38, 39,
300 36, 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 43, 40, 41, 41, 42,
301 42, 43, 44, 45, 45, 46, 46, 47, 32, 33, 33, 34, 34, 35, 36, 37,
302 37, 38, 38, 39, 36, 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 43,
303 40, 41, 41, 42, 42, 43, 44, 45, 45, 46, 46, 47, 48, 49, 49, 50,
304 50, 51, 52, 53, 53, 54, 54, 55, 52, 53, 53, 54, 54, 55, 56, 57,
305 57, 58, 58, 59, 56, 57, 57, 58, 58, 59, 60, 61, 61, 62, 62, 63,
306 48, 49, 49, 50, 50, 51, 52, 53, 53, 54, 54, 55, 52, 53, 53, 54,
307 54, 55, 56, 57, 57, 58, 58, 59, 56, 57, 57, 58, 58, 59, 60, 61,
308 61, 62, 62, 63, 64, 65, 65, 66, 66, 67, 68, 69, 69, 70, 70, 71,
309 68, 69, 69, 70, 70, 71, 72, 73, 73, 74, 74, 75, 72, 73, 73, 74,
310 74, 75, 76, 77, 77, 78, 78, 79, 0, 0, 80, 80, 80, 81, 81, 81,
311 82, 82, 82, 83, 83, 83, 84, 84, 84, 85, 85, 85, 86, 86, 86, 87
314 return (table[c]);