1 // Copyright 2022 Garrett D'Amore
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE or https://www.boost.org/LICENSE_1_0.txt)
5 
6 module dcell.color;
7 
8 import std.typecons;
9 
10 /// Color is a what you think, almost.
11 /// However, the upper bits of the color are used to indicate special behaviors.
12 /// If the value upper 24-bits are clear, then the value is an index into a
13 /// palette (typically it should be less than 256).  If the isRGB bit is
14 /// set, then the lower 24 bits are a 24-bit direct color (RGB).
15 enum Color : uint
16 {
17     none = 1 << 24, /// no color change
18     reset = none + 1, /// reset color to terminal defaults
19     invalid = none + 2, /// generically an invalid color
20     isRGB = 1 << 31, /// indicates that the low 24-bits are red, green blue
21     black = 0,
22     maroon = 1,
23     green = 2,
24     olive = 3,
25     navy = 4,
26     purple = 5,
27     teal = 6,
28     silver = 7,
29     gray = 8,
30     red = 9,
31     lime = 10,
32     yellow = 11,
33     blue = 12,
34     fuchsia = 13,
35     aqua = 14,
36     white = 15,
37     // following colors are web named colors
38     aliceBlue = isRGB | 0xF0F8FF,
39     antiqueWhite = isRGB | 0xFAEBD7,
40     aquamarine = isRGB | 0x7FFFD4,
41     azure = isRGB | 0xF0FFFF,
42     beige = isRGB | 0xF5F5DC,
43     bisque = isRGB | 0xFFE4C4,
44     blanchedAlmond = isRGB | 0xFFEBCD,
45     blueViolet = isRGB | 0x8A2BE2,
46     brown = isRGB | 0xA52A2A,
47     burlyWood = isRGB | 0xDEB887,
48     cadetBlue = isRGB | 0x5F9EA0,
49     chartreuse = isRGB | 0x7FFF00,
50     chocolate = isRGB | 0xD2691E,
51     coral = isRGB | 0xFF7F50,
52     cornflowerBlue = isRGB | 0x6495ED,
53     cornsilk = isRGB | 0xFFF8DC,
54     crimson = isRGB | 0xDC143C,
55     darkBlue = isRGB | 0x00008B,
56     darkCyan = isRGB | 0x008B8B,
57     darkGoldenrod = isRGB | 0xB8860B,
58     darkGray = isRGB | 0xA9A9A9,
59     darkGreen = isRGB | 0x006400,
60     darkKhaki = isRGB | 0xBDB76B,
61     darkMagenta = isRGB | 0x8B008B,
62     darkOliveGreen = isRGB | 0x556B2F,
63     darkOrange = isRGB | 0xFF8C00,
64     darkOrchid = isRGB | 0x9932CC,
65     darkRed = isRGB | 0x8B0000,
66     darkSalmon = isRGB | 0xE9967A,
67     darkSeaGreen = isRGB | 0x8FBC8F,
68     darkSlateBlue = isRGB | 0x483D8B,
69     darkSlateGray = isRGB | 0x2F4F4F,
70     darkTurquoise = isRGB | 0x00CED1,
71     darkViolet = isRGB | 0x9400D3,
72     deepPink = isRGB | 0xFF1493,
73     deepSkyBlue = isRGB | 0x00BFFF,
74     dimGray = isRGB | 0x696969,
75     dodgerBlue = isRGB | 0x1E90FF,
76     fireBrick = isRGB | 0xB22222,
77     floralWhite = isRGB | 0xFFFAF0,
78     forestGreen = isRGB | 0x228B22,
79     gainsboro = isRGB | 0xDCDCDC,
80     ghostWhite = isRGB | 0xF8F8FF,
81     gold = isRGB | 0xFFD700,
82     goldenrod = isRGB | 0xDAA520,
83     greenYellow = isRGB | 0xADFF2F,
84     honeydew = isRGB | 0xF0FFF0,
85     hotPink = isRGB | 0xFF69B4,
86     indianRed = isRGB | 0xCD5C5C,
87     indigo = isRGB | 0x4B0082,
88     ivory = isRGB | 0xFFFFF0,
89     khaki = isRGB | 0xF0E68C,
90     lavender = isRGB | 0xE6E6FA,
91     lavenderBlush = isRGB | 0xFFF0F5,
92     lawnGreen = isRGB | 0x7CFC00,
93     lemonChiffon = isRGB | 0xFFFACD,
94     lightBlue = isRGB | 0xADD8E6,
95     lightCoral = isRGB | 0xF08080,
96     lightCyan = isRGB | 0xE0FFFF,
97     lightGoldenrodYellow = isRGB | 0xFAFAD2,
98     lightGray = isRGB | 0xD3D3D3,
99     lightGreen = isRGB | 0x90EE90,
100     lightPink = isRGB | 0xFFB6C1,
101     lightSalmon = isRGB | 0xFFA07A,
102     lightSeaGreen = isRGB | 0x20B2AA,
103     lightSkyBlue = isRGB | 0x87CEFA,
104     lightSlateGray = isRGB | 0x778899,
105     lightSteelBlue = isRGB | 0xB0C4DE,
106     lightYellow = isRGB | 0xFFFFE0,
107     limeGreen = isRGB | 0x32CD32,
108     linen = isRGB | 0xFAF0E6,
109     mediumAquamarine = isRGB | 0x66CDAA,
110     mediumBlue = isRGB | 0x0000CD,
111     mediumOrchid = isRGB | 0xBA55D3,
112     mediumPurple = isRGB | 0x9370DB,
113     mediumSeaGreen = isRGB | 0x3CB371,
114     mediumSlateBlue = isRGB | 0x7B68EE,
115     mediumSpringGreen = isRGB | 0x00FA9A,
116     mediumTurquoise = isRGB | 0x48D1CC,
117     mediumVioletRed = isRGB | 0xC71585,
118     midnightBlue = isRGB | 0x191970,
119     mintCream = isRGB | 0xF5FFFA,
120     mistyRose = isRGB | 0xFFE4E1,
121     moccasin = isRGB | 0xFFE4B5,
122     navajoWhite = isRGB | 0xFFDEAD,
123     oldLace = isRGB | 0xFDF5E6,
124     oliveDrab = isRGB | 0x6B8E23,
125     orange = isRGB | 0xFFA500,
126     orangeRed = isRGB | 0xFF4500,
127     orchid = isRGB | 0xDA70D6,
128     paleGoldenrod = isRGB | 0xEEE8AA,
129     paleGreen = isRGB | 0x98FB98,
130     paleTurquoise = isRGB | 0xAFEEEE,
131     paleVioletRed = isRGB | 0xDB7093,
132     papayaWhip = isRGB | 0xFFEFD5,
133     peachPuff = isRGB | 0xFFDAB9,
134     peru = isRGB | 0xCD853F,
135     pink = isRGB | 0xFFC0CB,
136     plum = isRGB | 0xDDA0DD,
137     powderBlue = isRGB | 0xB0E0E6,
138     rebeccaPurple = isRGB | 0x663399,
139     rosyBrown = isRGB | 0xBC8F8F,
140     royalBlue = isRGB | 0x4169E1,
141     saddleBrown = isRGB | 0x8B4513,
142     salmon = isRGB | 0xFA8072,
143     sandyBrown = isRGB | 0xF4A460,
144     seaGreen = isRGB | 0x2E8B57,
145     seashell = isRGB | 0xFFF5EE,
146     sienna = isRGB | 0xA0522D,
147     skyBlue = isRGB | 0x87CEEB,
148     slateBlue = isRGB | 0x6A5ACD,
149     slateGray = isRGB | 0x708090,
150     snow = isRGB | 0xFFFAFA,
151     springGreen = isRGB | 0x00FF7F,
152     steelBlue = isRGB | 0x4682B4,
153     tan = isRGB | 0xD2B48C,
154     thistle = isRGB | 0xD8BFD8,
155     tomato = isRGB | 0xFF6347,
156     turquoise = isRGB | 0x40E0D0,
157     violet = isRGB | 0xEE82EE,
158     wheat = isRGB | 0xF5DEB3,
159     whiteSmoke = isRGB | 0xF5F5F5,
160     yellowGreen = isRGB | 0x9ACD32,
161 }
162 
163 private static immutable uint[Color] rgbValues;
164 private static immutable Color[uint] palValues;
165 
166 shared static this()
167 {
168     rgbValues[Color.black] = 0x000000;
169     rgbValues[Color.maroon] = 0x800000;
170     rgbValues[Color.green] = 0x008000;
171     rgbValues[Color.olive] = 0x808000;
172     rgbValues[Color.navy] = 0x000080;
173     rgbValues[Color.purple] = 0x800080;
174     rgbValues[Color.teal] = 0x008080;
175     rgbValues[Color.silver] = 0xC0C0C0;
176     rgbValues[Color.gray] = 0x808080;
177     rgbValues[Color.red] = 0xFF0000;
178     rgbValues[Color.lime] = 0x00FF00;
179     rgbValues[Color.yellow] = 0xFFFF00;
180     rgbValues[Color.blue] = 0x0000FF;
181     rgbValues[Color.fuchsia] = 0xFF00FF;
182     rgbValues[Color.aqua] = 0x00FFFF;
183     rgbValues[Color.white] = 0xFFFFFF;
184     // 256 color extended palette
185     rgbValues[cast(Color) 16] = 0x000000; // black
186     rgbValues[cast(Color) 17] = 0x00005F;
187     rgbValues[cast(Color) 18] = 0x000087;
188     rgbValues[cast(Color) 19] = 0x0000AF;
189     rgbValues[cast(Color) 20] = 0x0000D7;
190     rgbValues[cast(Color) 21] = 0x0000FF; // blue
191     rgbValues[cast(Color) 22] = 0x005F00;
192     rgbValues[cast(Color) 23] = 0x005F5F;
193     rgbValues[cast(Color) 24] = 0x005F87;
194     rgbValues[cast(Color) 25] = 0x005FAF;
195     rgbValues[cast(Color) 26] = 0x005FD7;
196     rgbValues[cast(Color) 27] = 0x005FFF;
197     rgbValues[cast(Color) 28] = 0x008700;
198     rgbValues[cast(Color) 29] = 0x00875F;
199     rgbValues[cast(Color) 30] = 0x008787;
200     rgbValues[cast(Color) 31] = 0x0087Af;
201     rgbValues[cast(Color) 32] = 0x0087D7;
202     rgbValues[cast(Color) 33] = 0x0087FF;
203     rgbValues[cast(Color) 34] = 0x00AF00;
204     rgbValues[cast(Color) 35] = 0x00AF5F;
205     rgbValues[cast(Color) 36] = 0x00AF87;
206     rgbValues[cast(Color) 37] = 0x00AFAF;
207     rgbValues[cast(Color) 38] = 0x00AFD7;
208     rgbValues[cast(Color) 39] = 0x00AFFF;
209     rgbValues[cast(Color) 40] = 0x00D700;
210     rgbValues[cast(Color) 41] = 0x00D75F;
211     rgbValues[cast(Color) 42] = 0x00D787;
212     rgbValues[cast(Color) 43] = 0x00D7AF;
213     rgbValues[cast(Color) 44] = 0x00D7D7;
214     rgbValues[cast(Color) 45] = 0x00D7FF;
215     rgbValues[cast(Color) 46] = 0x00FF00; // lime
216     rgbValues[cast(Color) 47] = 0x00FF5F;
217     rgbValues[cast(Color) 48] = 0x00FF87;
218     rgbValues[cast(Color) 49] = 0x00FFAF;
219     rgbValues[cast(Color) 50] = 0x00FFd7;
220     rgbValues[cast(Color) 51] = 0x00FFFF; // aqua
221     rgbValues[cast(Color) 52] = 0x5F0000;
222     rgbValues[cast(Color) 53] = 0x5F005F;
223     rgbValues[cast(Color) 54] = 0x5F0087;
224     rgbValues[cast(Color) 55] = 0x5F00AF;
225     rgbValues[cast(Color) 56] = 0x5F00D7;
226     rgbValues[cast(Color) 57] = 0x5F00FF;
227     rgbValues[cast(Color) 58] = 0x5F5F00;
228     rgbValues[cast(Color) 59] = 0x5F5F5F;
229     rgbValues[cast(Color) 60] = 0x5F5F87;
230     rgbValues[cast(Color) 61] = 0x5F5FAF;
231     rgbValues[cast(Color) 62] = 0x5F5FD7;
232     rgbValues[cast(Color) 63] = 0x5F5FFF;
233     rgbValues[cast(Color) 64] = 0x5F8700;
234     rgbValues[cast(Color) 65] = 0x5F875F;
235     rgbValues[cast(Color) 66] = 0x5F8787;
236     rgbValues[cast(Color) 67] = 0x5F87AF;
237     rgbValues[cast(Color) 68] = 0x5F87D7;
238     rgbValues[cast(Color) 69] = 0x5F87FF;
239     rgbValues[cast(Color) 70] = 0x5FAF00;
240     rgbValues[cast(Color) 71] = 0x5FAF5F;
241     rgbValues[cast(Color) 72] = 0x5FAF87;
242     rgbValues[cast(Color) 73] = 0x5FAFAF;
243     rgbValues[cast(Color) 74] = 0x5FAFD7;
244     rgbValues[cast(Color) 75] = 0x5FAFFF;
245     rgbValues[cast(Color) 76] = 0x5FD700;
246     rgbValues[cast(Color) 77] = 0x5FD75F;
247     rgbValues[cast(Color) 78] = 0x5FD787;
248     rgbValues[cast(Color) 79] = 0x5FD7AF;
249     rgbValues[cast(Color) 80] = 0x5FD7D7;
250     rgbValues[cast(Color) 81] = 0x5FD7FF;
251     rgbValues[cast(Color) 82] = 0x5FFF00;
252     rgbValues[cast(Color) 83] = 0x5FFF5F;
253     rgbValues[cast(Color) 84] = 0x5FFF87;
254     rgbValues[cast(Color) 85] = 0x5FFFAF;
255     rgbValues[cast(Color) 86] = 0x5FFFD7;
256     rgbValues[cast(Color) 87] = 0x5FFFFF;
257     rgbValues[cast(Color) 88] = 0x870000;
258     rgbValues[cast(Color) 89] = 0x87005F;
259     rgbValues[cast(Color) 90] = 0x870087;
260     rgbValues[cast(Color) 91] = 0x8700AF;
261     rgbValues[cast(Color) 92] = 0x8700D7;
262     rgbValues[cast(Color) 93] = 0x8700FF;
263     rgbValues[cast(Color) 94] = 0x875F00;
264     rgbValues[cast(Color) 95] = 0x875F5F;
265     rgbValues[cast(Color) 96] = 0x875F87;
266     rgbValues[cast(Color) 97] = 0x875FAF;
267     rgbValues[cast(Color) 98] = 0x875FD7;
268     rgbValues[cast(Color) 99] = 0x875FFF;
269     rgbValues[cast(Color) 100] = 0x878700;
270     rgbValues[cast(Color) 101] = 0x87875F;
271     rgbValues[cast(Color) 102] = 0x878787;
272     rgbValues[cast(Color) 103] = 0x8787AF;
273     rgbValues[cast(Color) 104] = 0x8787D7;
274     rgbValues[cast(Color) 105] = 0x8787FF;
275     rgbValues[cast(Color) 106] = 0x87AF00;
276     rgbValues[cast(Color) 107] = 0x87AF5F;
277     rgbValues[cast(Color) 108] = 0x87AF87;
278     rgbValues[cast(Color) 109] = 0x87AFAF;
279     rgbValues[cast(Color) 110] = 0x87AFD7;
280     rgbValues[cast(Color) 111] = 0x87AFFF;
281     rgbValues[cast(Color) 112] = 0x87D700;
282     rgbValues[cast(Color) 113] = 0x87D75F;
283     rgbValues[cast(Color) 114] = 0x87D787;
284     rgbValues[cast(Color) 115] = 0x87D7AF;
285     rgbValues[cast(Color) 116] = 0x87D7D7;
286     rgbValues[cast(Color) 117] = 0x87D7FF;
287     rgbValues[cast(Color) 118] = 0x87FF00;
288     rgbValues[cast(Color) 119] = 0x87FF5F;
289     rgbValues[cast(Color) 120] = 0x87FF87;
290     rgbValues[cast(Color) 121] = 0x87FFAF;
291     rgbValues[cast(Color) 122] = 0x87FFD7;
292     rgbValues[cast(Color) 123] = 0x87FFFF;
293     rgbValues[cast(Color) 124] = 0xAF0000;
294     rgbValues[cast(Color) 125] = 0xAF005F;
295     rgbValues[cast(Color) 126] = 0xAF0087;
296     rgbValues[cast(Color) 127] = 0xAF00AF;
297     rgbValues[cast(Color) 128] = 0xAF00D7;
298     rgbValues[cast(Color) 129] = 0xAF00FF;
299     rgbValues[cast(Color) 130] = 0xAF5F00;
300     rgbValues[cast(Color) 131] = 0xAF5F5F;
301     rgbValues[cast(Color) 132] = 0xAF5F87;
302     rgbValues[cast(Color) 133] = 0xAF5FAF;
303     rgbValues[cast(Color) 134] = 0xAF5FD7;
304     rgbValues[cast(Color) 135] = 0xAF5FFF;
305     rgbValues[cast(Color) 136] = 0xAF8700;
306     rgbValues[cast(Color) 137] = 0xAF875F;
307     rgbValues[cast(Color) 138] = 0xAF8787;
308     rgbValues[cast(Color) 139] = 0xAF87AF;
309     rgbValues[cast(Color) 140] = 0xAF87D7;
310     rgbValues[cast(Color) 141] = 0xAF87FF;
311     rgbValues[cast(Color) 142] = 0xAFAF00;
312     rgbValues[cast(Color) 143] = 0xAFAF5F;
313     rgbValues[cast(Color) 144] = 0xAFAF87;
314     rgbValues[cast(Color) 145] = 0xAFAFAF;
315     rgbValues[cast(Color) 146] = 0xAFAFD7;
316     rgbValues[cast(Color) 147] = 0xAFAFFF;
317     rgbValues[cast(Color) 148] = 0xAFD700;
318     rgbValues[cast(Color) 149] = 0xAFD75F;
319     rgbValues[cast(Color) 150] = 0xAFD787;
320     rgbValues[cast(Color) 151] = 0xAFD7AF;
321     rgbValues[cast(Color) 152] = 0xAFD7D7;
322     rgbValues[cast(Color) 153] = 0xAFD7FF;
323     rgbValues[cast(Color) 154] = 0xAFFF00;
324     rgbValues[cast(Color) 155] = 0xAFFF5F;
325     rgbValues[cast(Color) 156] = 0xAFFF87;
326     rgbValues[cast(Color) 157] = 0xAFFFAF;
327     rgbValues[cast(Color) 158] = 0xAFFFD7;
328     rgbValues[cast(Color) 159] = 0xAFFFFF;
329     rgbValues[cast(Color) 160] = 0xD70000;
330     rgbValues[cast(Color) 161] = 0xD7005F;
331     rgbValues[cast(Color) 162] = 0xD70087;
332     rgbValues[cast(Color) 163] = 0xD700AF;
333     rgbValues[cast(Color) 164] = 0xD700D7;
334     rgbValues[cast(Color) 165] = 0xD700FF;
335     rgbValues[cast(Color) 166] = 0xD75F00;
336     rgbValues[cast(Color) 167] = 0xD75F5F;
337     rgbValues[cast(Color) 168] = 0xD75F87;
338     rgbValues[cast(Color) 169] = 0xD75FAF;
339     rgbValues[cast(Color) 170] = 0xD75FD7;
340     rgbValues[cast(Color) 171] = 0xD75FFF;
341     rgbValues[cast(Color) 172] = 0xD78700;
342     rgbValues[cast(Color) 173] = 0xD7875F;
343     rgbValues[cast(Color) 174] = 0xD78787;
344     rgbValues[cast(Color) 175] = 0xD787AF;
345     rgbValues[cast(Color) 176] = 0xD787D7;
346     rgbValues[cast(Color) 177] = 0xD787FF;
347     rgbValues[cast(Color) 178] = 0xD7AF00;
348     rgbValues[cast(Color) 179] = 0xD7AF5F;
349     rgbValues[cast(Color) 180] = 0xD7AF87;
350     rgbValues[cast(Color) 181] = 0xD7AFAF;
351     rgbValues[cast(Color) 182] = 0xD7AFD7;
352     rgbValues[cast(Color) 183] = 0xD7AFFF;
353     rgbValues[cast(Color) 184] = 0xD7D700;
354     rgbValues[cast(Color) 185] = 0xD7D75F;
355     rgbValues[cast(Color) 186] = 0xD7D787;
356     rgbValues[cast(Color) 187] = 0xD7D7AF;
357     rgbValues[cast(Color) 188] = 0xD7D7D7;
358     rgbValues[cast(Color) 189] = 0xD7D7FF;
359     rgbValues[cast(Color) 190] = 0xD7FF00;
360     rgbValues[cast(Color) 191] = 0xD7FF5F;
361     rgbValues[cast(Color) 192] = 0xD7FF87;
362     rgbValues[cast(Color) 193] = 0xD7FFAF;
363     rgbValues[cast(Color) 194] = 0xD7FFD7;
364     rgbValues[cast(Color) 195] = 0xD7FFFF;
365     rgbValues[cast(Color) 196] = 0xFF0000; // red
366     rgbValues[cast(Color) 197] = 0xFF005F;
367     rgbValues[cast(Color) 198] = 0xFF0087;
368     rgbValues[cast(Color) 199] = 0xFF00AF;
369     rgbValues[cast(Color) 200] = 0xFF00D7;
370     rgbValues[cast(Color) 201] = 0xFF00FF; // fuchsia
371     rgbValues[cast(Color) 202] = 0xFF5F00;
372     rgbValues[cast(Color) 203] = 0xFF5F5F;
373     rgbValues[cast(Color) 204] = 0xFF5F87;
374     rgbValues[cast(Color) 205] = 0xFF5FAF;
375     rgbValues[cast(Color) 206] = 0xFF5FD7;
376     rgbValues[cast(Color) 207] = 0xFF5FFF;
377     rgbValues[cast(Color) 208] = 0xFF8700;
378     rgbValues[cast(Color) 209] = 0xFF875F;
379     rgbValues[cast(Color) 210] = 0xFF8787;
380     rgbValues[cast(Color) 211] = 0xFF87AF;
381     rgbValues[cast(Color) 212] = 0xFF87D7;
382     rgbValues[cast(Color) 213] = 0xFF87FF;
383     rgbValues[cast(Color) 214] = 0xFFAF00;
384     rgbValues[cast(Color) 215] = 0xFFAF5F;
385     rgbValues[cast(Color) 216] = 0xFFAF87;
386     rgbValues[cast(Color) 217] = 0xFFAFAF;
387     rgbValues[cast(Color) 218] = 0xFFAFD7;
388     rgbValues[cast(Color) 219] = 0xFFAFFF;
389     rgbValues[cast(Color) 220] = 0xFFD700;
390     rgbValues[cast(Color) 221] = 0xFFD75F;
391     rgbValues[cast(Color) 222] = 0xFFD787;
392     rgbValues[cast(Color) 223] = 0xFFD7AF;
393     rgbValues[cast(Color) 224] = 0xFFD7D7;
394     rgbValues[cast(Color) 225] = 0xFFD7FF;
395     rgbValues[cast(Color) 226] = 0xFFFF00; // yellow
396     rgbValues[cast(Color) 227] = 0xFFFF5F;
397     rgbValues[cast(Color) 228] = 0xFFFF87;
398     rgbValues[cast(Color) 229] = 0xFFFFAF;
399     rgbValues[cast(Color) 230] = 0xFFFFD7;
400     rgbValues[cast(Color) 231] = 0xFFFFFF; // white
401     rgbValues[cast(Color) 232] = 0x080808;
402     rgbValues[cast(Color) 233] = 0x121212;
403     rgbValues[cast(Color) 234] = 0x1C1C1C;
404     rgbValues[cast(Color) 235] = 0x262626;
405     rgbValues[cast(Color) 236] = 0x303030;
406     rgbValues[cast(Color) 237] = 0x3A3A3A;
407     rgbValues[cast(Color) 238] = 0x444444;
408     rgbValues[cast(Color) 239] = 0x4E4E4E;
409     rgbValues[cast(Color) 240] = 0x585858;
410     rgbValues[cast(Color) 241] = 0x626262;
411     rgbValues[cast(Color) 242] = 0x6C6C6C;
412     rgbValues[cast(Color) 243] = 0x767676;
413     rgbValues[cast(Color) 244] = 0x808080; // grey
414     rgbValues[cast(Color) 245] = 0x8A8A8A;
415     rgbValues[cast(Color) 246] = 0x949494;
416     rgbValues[cast(Color) 247] = 0x9E9E9E;
417     rgbValues[cast(Color) 248] = 0xA8A8A8;
418     rgbValues[cast(Color) 249] = 0xB2B2B2;
419     rgbValues[cast(Color) 250] = 0xBCBCBC;
420     rgbValues[cast(Color) 251] = 0xC6C6C6;
421     rgbValues[cast(Color) 252] = 0xD0D0D0;
422     rgbValues[cast(Color) 253] = 0xDADADA;
423     rgbValues[cast(Color) 254] = 0xE4E4E4;
424     rgbValues[cast(Color) 255] = 0xEEEEEE;
425 
426     palValues[0x000000] = Color.black;
427     palValues[0x800000] = Color.maroon;
428     palValues[0x008000] = Color.green;
429     palValues[0x808000] = Color.olive;
430     palValues[0x000080] = Color.navy;
431     palValues[0x800080] = Color.purple;
432     palValues[0x008080] = Color.teal;
433     palValues[0xC0C0C0] = Color.silver;
434     palValues[0x808080] = Color.gray;
435     palValues[0xFF0000] = Color.red;
436     palValues[0x00FF00] = Color.lime;
437     palValues[0xFFFF00] = Color.yellow;
438     palValues[0x0000FF] = Color.blue;
439     palValues[0xFF00FF] = Color.fuchsia;
440     palValues[0x00FFFF] = Color.aqua;
441     palValues[0xFFFFFF] = Color.white;
442     // palValues[0x000000] = cast(Color) 16; // black
443     palValues[0x00005F] = cast(Color) 17;
444     palValues[0x000087] = cast(Color) 18;
445     palValues[0x0000AF] = cast(Color) 19;
446     palValues[0x0000D7] = cast(Color) 20;
447     // palValues[0x0000FF] = cast(Color) 21; // blue
448     palValues[0x005F00] = cast(Color) 22;
449     palValues[0x005F5F] = cast(Color) 23;
450     palValues[0x005F87] = cast(Color) 24;
451     palValues[0x005FAF] = cast(Color) 25;
452     palValues[0x005FD7] = cast(Color) 26;
453     palValues[0x005FFF] = cast(Color) 27;
454     palValues[0x008700] = cast(Color) 28;
455     palValues[0x00875F] = cast(Color) 29;
456     palValues[0x008787] = cast(Color) 30;
457     palValues[0x0087Af] = cast(Color) 31;
458     palValues[0x0087D7] = cast(Color) 32;
459     palValues[0x0087FF] = cast(Color) 33;
460     palValues[0x00AF00] = cast(Color) 34;
461     palValues[0x00AF5F] = cast(Color) 35;
462     palValues[0x00AF87] = cast(Color) 36;
463     palValues[0x00AFAF] = cast(Color) 37;
464     palValues[0x00AFD7] = cast(Color) 38;
465     palValues[0x00AFFF] = cast(Color) 39;
466     palValues[0x00D700] = cast(Color) 40;
467     palValues[0x00D75F] = cast(Color) 41;
468     palValues[0x00D787] = cast(Color) 42;
469     palValues[0x00D7AF] = cast(Color) 43;
470     palValues[0x00D7D7] = cast(Color) 44;
471     palValues[0x00D7FF] = cast(Color) 45;
472     // palValues[0x00FF00] = cast(Color) 46; // lime
473     palValues[0x00FF5F] = cast(Color) 47;
474     palValues[0x00FF87] = cast(Color) 48;
475     palValues[0x00FFAF] = cast(Color) 49;
476     palValues[0x00FFd7] = cast(Color) 50;
477     // palValues[0x00FFFF] = cast(Color) 51; // aqua
478     palValues[0x5F0000] = cast(Color) 52;
479     palValues[0x5F005F] = cast(Color) 53;
480     palValues[0x5F0087] = cast(Color) 54;
481     palValues[0x5F00AF] = cast(Color) 55;
482     palValues[0x5F00D7] = cast(Color) 56;
483     palValues[0x5F00FF] = cast(Color) 57;
484     palValues[0x5F5F00] = cast(Color) 58;
485     palValues[0x5F5F5F] = cast(Color) 59;
486     palValues[0x5F5F87] = cast(Color) 60;
487     palValues[0x5F5FAF] = cast(Color) 61;
488     palValues[0x5F5FD7] = cast(Color) 62;
489     palValues[0x5F5FFF] = cast(Color) 63;
490     palValues[0x5F8700] = cast(Color) 64;
491     palValues[0x5F875F] = cast(Color) 65;
492     palValues[0x5F8787] = cast(Color) 66;
493     palValues[0x5F87AF] = cast(Color) 67;
494     palValues[0x5F87D7] = cast(Color) 68;
495     palValues[0x5F87FF] = cast(Color) 69;
496     palValues[0x5FAF00] = cast(Color) 70;
497     palValues[0x5FAF5F] = cast(Color) 71;
498     palValues[0x5FAF87] = cast(Color) 72;
499     palValues[0x5FAFAF] = cast(Color) 73;
500     palValues[0x5FAFD7] = cast(Color) 74;
501     palValues[0x5FAFFF] = cast(Color) 75;
502     palValues[0x5FD700] = cast(Color) 76;
503     palValues[0x5FD75F] = cast(Color) 77;
504     palValues[0x5FD787] = cast(Color) 78;
505     palValues[0x5FD7AF] = cast(Color) 79;
506     palValues[0x5FD7D7] = cast(Color) 80;
507     palValues[0x5FD7FF] = cast(Color) 81;
508     palValues[0x5FFF00] = cast(Color) 82;
509     palValues[0x5FFF5F] = cast(Color) 83;
510     palValues[0x5FFF87] = cast(Color) 84;
511     palValues[0x5FFFAF] = cast(Color) 85;
512     palValues[0x5FFFD7] = cast(Color) 86;
513     palValues[0x5FFFFF] = cast(Color) 87;
514     palValues[0x870000] = cast(Color) 88;
515     palValues[0x87005F] = cast(Color) 89;
516     palValues[0x870087] = cast(Color) 90;
517     palValues[0x8700AF] = cast(Color) 91;
518     palValues[0x8700D7] = cast(Color) 92;
519     palValues[0x8700FF] = cast(Color) 93;
520     palValues[0x875F00] = cast(Color) 94;
521     palValues[0x875F5F] = cast(Color) 95;
522     palValues[0x875F87] = cast(Color) 96;
523     palValues[0x875FAF] = cast(Color) 97;
524     palValues[0x875FD7] = cast(Color) 98;
525     palValues[0x875FFF] = cast(Color) 99;
526     palValues[0x878700] = cast(Color) 100;
527     palValues[0x87875F] = cast(Color) 101;
528     palValues[0x878787] = cast(Color) 102;
529     palValues[0x8787AF] = cast(Color) 103;
530     palValues[0x8787D7] = cast(Color) 104;
531     palValues[0x8787FF] = cast(Color) 105;
532     palValues[0x87AF00] = cast(Color) 106;
533     palValues[0x87AF5F] = cast(Color) 107;
534     palValues[0x87AF87] = cast(Color) 108;
535     palValues[0x87AFAF] = cast(Color) 109;
536     palValues[0x87AFD7] = cast(Color) 110;
537     palValues[0x87AFFF] = cast(Color) 111;
538     palValues[0x87D700] = cast(Color) 112;
539     palValues[0x87D75F] = cast(Color) 113;
540     palValues[0x87D787] = cast(Color) 114;
541     palValues[0x87D7AF] = cast(Color) 115;
542     palValues[0x87D7D7] = cast(Color) 116;
543     palValues[0x87D7FF] = cast(Color) 117;
544     palValues[0x87FF00] = cast(Color) 118;
545     palValues[0x87FF5F] = cast(Color) 119;
546     palValues[0x87FF87] = cast(Color) 120;
547     palValues[0x87FFAF] = cast(Color) 121;
548     palValues[0x87FFD7] = cast(Color) 122;
549     palValues[0x87FFFF] = cast(Color) 123;
550     palValues[0xAF0000] = cast(Color) 124;
551     palValues[0xAF005F] = cast(Color) 125;
552     palValues[0xAF0087] = cast(Color) 126;
553     palValues[0xAF00AF] = cast(Color) 127;
554     palValues[0xAF00D7] = cast(Color) 128;
555     palValues[0xAF00FF] = cast(Color) 129;
556     palValues[0xAF5F00] = cast(Color) 130;
557     palValues[0xAF5F5F] = cast(Color) 131;
558     palValues[0xAF5F87] = cast(Color) 132;
559     palValues[0xAF5FAF] = cast(Color) 133;
560     palValues[0xAF5FD7] = cast(Color) 134;
561     palValues[0xAF5FFF] = cast(Color) 135;
562     palValues[0xAF8700] = cast(Color) 136;
563     palValues[0xAF875F] = cast(Color) 137;
564     palValues[0xAF8787] = cast(Color) 138;
565     palValues[0xAF87AF] = cast(Color) 139;
566     palValues[0xAF87D7] = cast(Color) 140;
567     palValues[0xAF87FF] = cast(Color) 141;
568     palValues[0xAFAF00] = cast(Color) 142;
569     palValues[0xAFAF5F] = cast(Color) 143;
570     palValues[0xAFAF87] = cast(Color) 144;
571     palValues[0xAFAFAF] = cast(Color) 145;
572     palValues[0xAFAFD7] = cast(Color) 146;
573     palValues[0xAFAFFF] = cast(Color) 147;
574     palValues[0xAFD700] = cast(Color) 148;
575     palValues[0xAFD75F] = cast(Color) 149;
576     palValues[0xAFD787] = cast(Color) 150;
577     palValues[0xAFD7AF] = cast(Color) 151;
578     palValues[0xAFD7D7] = cast(Color) 152;
579     palValues[0xAFD7FF] = cast(Color) 153;
580     palValues[0xAFFF00] = cast(Color) 154;
581     palValues[0xAFFF5F] = cast(Color) 155;
582     palValues[0xAFFF87] = cast(Color) 156;
583     palValues[0xAFFFAF] = cast(Color) 157;
584     palValues[0xAFFFD7] = cast(Color) 158;
585     palValues[0xAFFFFF] = cast(Color) 159;
586     palValues[0xD70000] = cast(Color) 160;
587     palValues[0xD7005F] = cast(Color) 161;
588     palValues[0xD70087] = cast(Color) 162;
589     palValues[0xD700AF] = cast(Color) 163;
590     palValues[0xD700D7] = cast(Color) 164;
591     palValues[0xD700FF] = cast(Color) 165;
592     palValues[0xD75F00] = cast(Color) 166;
593     palValues[0xD75F5F] = cast(Color) 167;
594     palValues[0xD75F87] = cast(Color) 168;
595     palValues[0xD75FAF] = cast(Color) 169;
596     palValues[0xD75FD7] = cast(Color) 170;
597     palValues[0xD75FFF] = cast(Color) 171;
598     palValues[0xD78700] = cast(Color) 172;
599     palValues[0xD7875F] = cast(Color) 173;
600     palValues[0xD78787] = cast(Color) 174;
601     palValues[0xD787AF] = cast(Color) 175;
602     palValues[0xD787D7] = cast(Color) 176;
603     palValues[0xD787FF] = cast(Color) 177;
604     palValues[0xD7AF00] = cast(Color) 178;
605     palValues[0xD7AF5F] = cast(Color) 179;
606     palValues[0xD7AF87] = cast(Color) 180;
607     palValues[0xD7AFAF] = cast(Color) 181;
608     palValues[0xD7AFD7] = cast(Color) 182;
609     palValues[0xD7AFFF] = cast(Color) 183;
610     palValues[0xD7D700] = cast(Color) 184;
611     palValues[0xD7D75F] = cast(Color) 185;
612     palValues[0xD7D787] = cast(Color) 186;
613     palValues[0xD7D7AF] = cast(Color) 187;
614     palValues[0xD7D7D7] = cast(Color) 188;
615     palValues[0xD7D7FF] = cast(Color) 189;
616     palValues[0xD7FF00] = cast(Color) 190;
617     palValues[0xD7FF5F] = cast(Color) 191;
618     palValues[0xD7FF87] = cast(Color) 192;
619     palValues[0xD7FFAF] = cast(Color) 193;
620     palValues[0xD7FFD7] = cast(Color) 194;
621     palValues[0xD7FFFF] = cast(Color) 195;
622     // palValues[0xFF0000] = cast(Color) 196; // red
623     palValues[0xFF005F] = cast(Color) 197;
624     palValues[0xFF0087] = cast(Color) 198;
625     palValues[0xFF00AF] = cast(Color) 199;
626     palValues[0xFF00D7] = cast(Color) 200;
627     // palValues[0xFF00FF] = cast(Color) 201; // fuchsia
628     palValues[0xFF5F00] = cast(Color) 202;
629     palValues[0xFF5F5F] = cast(Color) 203;
630     palValues[0xFF5F87] = cast(Color) 204;
631     palValues[0xFF5FAF] = cast(Color) 205;
632     palValues[0xFF5FD7] = cast(Color) 206;
633     palValues[0xFF5FFF] = cast(Color) 207;
634     palValues[0xFF8700] = cast(Color) 208;
635     palValues[0xFF875F] = cast(Color) 209;
636     palValues[0xFF8787] = cast(Color) 210;
637     palValues[0xFF87AF] = cast(Color) 211;
638     palValues[0xFF87D7] = cast(Color) 212;
639     palValues[0xFF87FF] = cast(Color) 213;
640     palValues[0xFFAF00] = cast(Color) 214;
641     palValues[0xFFAF5F] = cast(Color) 215;
642     palValues[0xFFAF87] = cast(Color) 216;
643     palValues[0xFFAFAF] = cast(Color) 217;
644     palValues[0xFFAFD7] = cast(Color) 218;
645     palValues[0xFFAFFF] = cast(Color) 219;
646     palValues[0xFFD700] = cast(Color) 220;
647     palValues[0xFFD75F] = cast(Color) 221;
648     palValues[0xFFD787] = cast(Color) 222;
649     palValues[0xFFD7AF] = cast(Color) 223;
650     palValues[0xFFD7D7] = cast(Color) 224;
651     palValues[0xFFD7FF] = cast(Color) 225;
652     // palValues[0xFFFF00] = cast(Color) 226; // yellow
653     palValues[0xFFFF5F] = cast(Color) 227;
654     palValues[0xFFFF87] = cast(Color) 228;
655     palValues[0xFFFFAF] = cast(Color) 229;
656     palValues[0xFFFFD7] = cast(Color) 230;
657     // palValues[0xFFFFFF] = cast(Color) 231; // white
658     palValues[0x080808] = cast(Color) 232;
659     palValues[0x121212] = cast(Color) 233;
660     palValues[0x1C1C1C] = cast(Color) 234;
661     palValues[0x262626] = cast(Color) 235;
662     palValues[0x303030] = cast(Color) 236;
663     palValues[0x3A3A3A] = cast(Color) 237;
664     palValues[0x444444] = cast(Color) 238;
665     palValues[0x4E4E4E] = cast(Color) 239;
666     palValues[0x585858] = cast(Color) 240;
667     palValues[0x626262] = cast(Color) 241;
668     palValues[0x6C6C6C] = cast(Color) 242;
669     palValues[0x767676] = cast(Color) 243;
670     // palValues[0x808080] = cast(Color) 244; // grey
671     palValues[0x8A8A8A] = cast(Color) 245;
672     palValues[0x949494] = cast(Color) 246;
673     palValues[0x9E9E9E] = cast(Color) 247;
674     palValues[0xA8A8A8] = cast(Color) 248;
675     palValues[0xB2B2B2] = cast(Color) 249;
676     palValues[0xBCBCBC] = cast(Color) 250;
677     palValues[0xC6C6C6] = cast(Color) 251;
678     palValues[0xD0D0D0] = cast(Color) 252;
679     palValues[0xDADADA] = cast(Color) 253;
680     palValues[0xE4E4E4] = cast(Color) 254;
681     palValues[0xEEEEEE] = cast(Color) 255;
682 }
683 
684 /// Obtain the numeric value of the RGB for the color.
685 ///
686 /// Params:
687 ///  c = a Color
688 /// Returns: Numeric RGB value for color, or -1 if it cannot be represented.
689 int toHex(Color c) pure
690 {
691     if ((c & Color.isRGB) != 0)
692     {
693         return (c & 0xffffff);
694     }
695     if (c in rgbValues)
696     {
697         return rgbValues[c];
698     }
699     return (-1);
700 }
701 
702 /// Create a color from RGB values.
703 /// 
704 /// Params:
705 ///   rgb = hex value, red << 16 | green << 8 | blue
706 /// Returns: The associated Color, or Color.invalid if a bad value for rgb was supplied.
707 Color fromHex(int rgb) pure
708 {
709     if (rgb < 1 << 24)
710     {
711         return cast(Color) rgb | Color.isRGB;
712     }
713     return Color.invalid;
714 }
715 
716 /// Convert a color to RGB form.  This is useful to convert
717 /// palette based colors to their full RGB values, which will provide
718 /// fidelity when the terminal supports it, but consequently does not
719 /// honor terminal preferences for color palettes.
720 ///
721 /// Params:
722 ///   c = a valid Color   
723 /// Returns: An RGB format Color, Color.invalid if it cannot be determined.
724 Color toRGB(Color c) pure
725 {
726     if ((c & Color.isRGB) != 0)
727     {
728         return c;
729     }
730     if (c in rgbValues)
731     {
732         return cast(Color) rgbValues[c] | Color.isRGB;
733     }
734     return Color.invalid;
735 }
736 
737 /// Is the color in RGB format? RGB format colors will try to be accurate
738 /// on the terminal, and will not honor user preferences.
739 /// Params:
740 ///   c = a valid color
741 /// Returns: true if the color is an RGB format color
742 bool isRGB(Color c) pure
743 {
744     return (c & Color.isRGB) != 0;
745 }
746 
747 /// Given a color, try to find an associated palette entry for it.
748 /// This will try to find the lowest numbered palette entry.
749 /// The palette entry might be a higher numbered color than the
750 /// terminal can support, if it does not support a 256 color palette.
751 /// 
752 /// Params:
753 ///   c = a valid Color
754 ///   numColors = the size of the palette
755 ///
756 /// Returns: the palette Color closest matching c
757 Color toPalette(Color c, int numColors)
758 {
759     import std.functional;
760 
761     switch (c)
762     {
763     case Color.none, Color.reset, Color.invalid:
764         return c;
765     default:
766         return memoize!bestColor(c, numColors);
767     }
768 }
769 
770 /// Return true if c1 is darker than c2.
771 bool darker(Color c1, Color c2)
772 {
773     import std.functional;
774 
775     auto d1 = memoize!redMean(c1, Color.black);
776     auto d2 = memoize!redMean(c2, Color.black);
777     return (d1 < d2);
778 }
779 
780 /**
781  * decompose a color into red, green, and blue values.
782  */
783 auto decompose(Color c) pure
784 {
785     c = toRGB(c);
786     return Tuple!(int, int, int)((c & 0xff0000) >> 16, ((c & 0xff00) >> 8), (c & 0xff));
787 }
788 
789 void decompose(Color c, ref int r, ref int g, ref int b) pure
790 {
791     c = toRGB(c);
792     r = int(c & 0xff0000) >> 16;
793     g = int(c & 0xff00) >> 8;
794     b = int(c & 0xff);
795 }
796 
797 unittest
798 {
799     assert(toPalette(Color.red, 16) == Color.red);
800     assert(toPalette(cast(Color) 0x00FF00 | Color.isRGB, 16) == Color.lime);
801     assert(toHex(Color.invalid) == -1);
802     assert(toRGB(cast(Color) 512) == Color.invalid);
803     assert(toRGB(Color.reset) == Color.invalid);
804     assert(fromHex(cast(int) Color.reset) == Color.invalid);
805     for (int i = 0; i < 256; i++)
806     {
807         auto r = toHex(cast(Color) i);
808         assert(r >= 0);
809         auto c = fromHex(r);
810         assert(toRGB(c) == c);
811         assert(c != Color.invalid);
812         auto p = toPalette(c, 256);
813         assert(p != Color.invalid);
814         if (i < 16)
815         {
816             assert(p == i);
817         }
818         else
819         {
820             assert(p < 256);
821             if (p > 15) // sometimes we map to a lower palette color
822             {
823                 assert(p == i);
824             }
825         }
826     }
827     for (Color c = Color.black; c <= Color.white; c++)
828     {
829         assert(toPalette(toRGB(c), 256) == c);
830     }
831     assert(decompose(Color.yellowGreen)[0] == 0x9a);
832     assert(decompose(Color.yellowGreen)[1] == 0xcd);
833     assert(decompose(Color.yellowGreen)[2] == 0x32);
834     assert(decompose(Color.red)[0] == 0xff);
835     assert(decompose(Color.red)[1] == 0);
836     assert(decompose(Color.red)[2] == 0);
837 }
838 
839 private long redMean(Color c1, Color c2) pure
840 {
841     int r1, r2, g1, g2, b1, b2;
842     decompose(c1, r1, g1, b1);
843     decompose(c2, r2, g2, b2);
844     long ar = (r1 + r2) / 2;
845     long dr = (r1 - r2);
846     long dg = (g1 - g2);
847     long db = (b1 - b2);
848 
849     long dist;
850 
851     // see https://en.wikipedia.org/wiki/Color_difference
852     dist = ((2 + ar / 256) * dr * dr) + (4 * dg * dg) + ((2 + ((255 - ar) / 256)) * db * db);
853 
854     // not bothering with the square root, since we are just comparing values
855     return dist;
856 }
857 
858 private Color bestColor(Color c, int numColors) pure
859 {
860     // this is an expensive operation, so you really want
861     // to memoize it.
862     long abs(long a) pure
863     {
864         return a >= 0 ? a : -a;
865     }
866 
867     c = toRGB(c);
868     if (c == Color.invalid)
869     {
870         return c;
871     }
872 
873     // look for a perfect fit first before we start doing hard math
874     auto hex = toHex(c);
875     if ((hex in palValues) && (palValues[hex] <= numColors))
876     {
877         return (palValues[hex]);
878     }
879 
880     if (numColors == 0)
881     {
882         auto d1 = redMean(c, Color.black);
883         auto d2 = redMean(c, Color.white);
884         return abs(d1) < abs(d2) ? Color.black : Color.white;
885     }
886     if (numColors > 256)
887     {
888         numColors = 256;
889     }
890     auto bestDist = long.max;
891     auto bestColor = Color.invalid;
892     for (Color pal = Color.black; pal < numColors; pal++)
893     {
894         auto d = redMean(c, toRGB(pal));
895         if (d < bestDist)
896         {
897             bestDist = d;
898             bestColor = pal;
899         }
900     }
901 
902     return (bestColor);
903 }
904 
905 unittest
906 {
907     import std.stdio;
908 
909     assert(bestColor(Color.red, 16) == Color.red);
910     assert(bestColor(Color.red, 256) == Color.red);
911     assert(bestColor(Color.paleGreen, 256) == cast(Color) 120);
912     assert(bestColor(Color.darkSlateBlue, 256) == cast(Color) 60);
913     assert(bestColor(fromHex(0xfe0000), 16) == Color.red);
914 }
915 
916 unittest
917 {
918     import std.stdio;
919 
920     assert(toPalette(Color.red, 16) == Color.red);
921     assert(toPalette(Color.red, 256) == Color.red);
922     assert(toPalette(Color.paleGreen, 256) == cast(Color) 120);
923     assert(toPalette(Color.darkSlateBlue, 256) == cast(Color) 60);
924     assert(toPalette(fromHex(0xfe0000), 16) == Color.red);
925 }