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