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