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