compiler/libec: (#341, #351, #644, #771) Improved enum type matching and type handlin...
[sdk] / ecere / src / gfx / Color.ec
1 namespace gfx;
2
3 import "ListBox"
4 import "DropBox"
5 import "ColorPicker"
6
7 public struct ColorRGB { float r, g, b; };
8 public struct ColorRGBAf
9 {
10    float r, g, b, a;
11
12    property ColorAlpha
13    {
14       set { this = ColorRGBAf { value.color.r/255.0f, value.color.g/255.0f, value.color.b/255.0f, value.a/255.0f }; }
15       get { return ColorAlpha { (byte)(a * 255), Color { (byte)(r * 255), (byte)(g * 255), (byte)(b * 255) } }; }
16    }
17    property Color
18    {
19       set { this = ColorRGBAf { value.r/255.0f, value.g/255.0f, value.b/255.0f, 1.0f }; }
20       get { return Color { (byte)(r * 255), (byte)(g * 255), (byte)(b * 255) }; }
21    }
22 };
23
24 public class Color : uint
25 {
26 public:
27    byte r:8:16, g:8:8, b:8:0;
28    property ColorRGB
29    {
30       get { value = ColorRGB { r/255.0f, g/255.0f, b/255.0f }; }
31       set { return Color { (byte)(value.r*255), (byte)(value.g*255), (byte)(value.b*255) }; }
32    }
33
34    bool OnSaveEdit(DropBox dropBox, void * object)
35    {
36       return dropBox.Save();
37    }
38
39    Window OnEdit(Window dataBox, Window master, int x, int y, int w, int h, Window control)
40    {
41       Size size = { 0 };
42       char * string = "";
43       ColorDropBox colorDropBox
44       {
45          dataBox, master = master, editText = true, //position = Point { x + 24, y }, /*clientSize.h = */size.h = h, size.w = w - 24,
46          anchor = { left = 24, top = 0, right = 0, bottom = 0 },
47          color = this, control = control
48       };
49       colorDropBox.Create();
50
51       //if(this)
52       {
53          char tempString[MAX_F_STRING];
54          char * result;
55          bool needClass = false;
56          tempString[0] = 0;
57          result = OnGetString(tempString, null, &needClass);
58          if(result) string = result;
59       }
60       colorDropBox.contents = string;
61       // This is to highlight text on DataBox::Refresh
62       colorDropBox.editBox.SelectAll();
63       return colorDropBox;
64    }
65
66    char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
67    {
68       char * string;
69       if((string = ((DefinedColor)this).class::OnGetString(stringOutput, null, needClass)) ||
70          (string = ((SystemColor)this).class::OnGetString(stringOutput, null, needClass)))
71       {
72          if(needClass) *needClass = false;
73          return string;
74       }
75       else
76       {
77          char tempString[256];
78          char * colorValue;
79          bool subNeedClass;
80          int value;
81
82          tempString[0] = '\0';
83          value = r;
84          colorValue = value.OnGetString(tempString, null, &subNeedClass);
85          strcpy(stringOutput, "r = "); strcat(stringOutput, colorValue);
86
87          // Weird bug in VS
88          memset(tempString, 0, 256);
89          tempString[0] = '\0';
90
91          value = g;
92          colorValue = value.OnGetString(tempString, null, &subNeedClass);
93          strcat(stringOutput, ", g = "); strcat(stringOutput, colorValue);
94
95          // Weird bug in VS
96          memset(tempString, 0, 256);
97          tempString[0] = '\0';
98
99          value = b;
100          colorValue = value.OnGetString(tempString, null, &subNeedClass);
101          strcat(stringOutput, ", b = "); strcat(stringOutput, colorValue);
102          return stringOutput;
103       }
104    }
105
106    bool OnGetDataFromString(char * string)
107    {
108       if(!atoi(string) && (((DefinedColor)this).class::OnGetDataFromString(string) ||
109          ((SystemColor)this).class::OnGetDataFromString(string)))
110          return true;
111       else
112          return class::OnGetDataFromString(string);
113    }
114
115    void OnDisplay(Surface surface, int x, int y, int width, char * fieldData, Alignment alignment, DataDisplayFlags displayFlags)
116    {
117       char tempString[1024] = "";
118       bool needClass = false;
119       // TODO: This isn't an ideal way of obtaining the clipped height, will fail on hidden areas
120       // This doesn't seem to help anymore?
121       // - Makes SavingDataBox draw at 2 different spots depending if active or not.
122       // - Color property in IDE is fine as well
123       // - How is it on Linux?
124       int yOffset = 0;//(1+surface.box.bottom - surface.box.top - 17)/2;
125       char * string = OnGetString(tempString, null, &needClass);
126       surface.WriteTextDots(alignment, x + 24, y + 1, width - 24, string, strlen(string));
127
128       // Erase background?
129       y += yOffset-1;
130       surface.SetBackground(white);
131       surface.Area(x - 4, y, x + 20, y + 15);
132
133       surface.SetBackground(this);
134       surface.Area(x, y + 2, x+17, y+13);
135       surface.SetForeground(black);
136       surface.Rectangle(x-1, y + 1, x + 18, y + 14);
137    }
138 }
139
140 public struct ColorHSV
141 {
142    Degrees h;
143    float s,v;
144
145    property ColorRGB
146    {
147       set
148       {
149          float r = value.r, g = value.g, b = value.b;
150          float minV, maxV, diff,dr,dg,db;
151
152          float h, s, v;
153
154          minV = Min(r, g);
155          minV = Min(minV, b);
156
157          maxV = Max(r, g);
158          maxV = Max(maxV, b);
159
160          diff = maxV - minV;
161          v = maxV;
162          if(diff)
163          {
164             s = diff/maxV;
165             dr = (maxV - r)/diff;
166             dg = (maxV - g)/diff;
167             db = (maxV - b)/diff;
168
169             /*
170                 if R=V then -- between yellow and magenta [degrees]
171                   H=60.0*(G-B)/Delta
172                 else if G=V then -- between cyan and yellow
173                     H=120.0+60.0*(B-R)/Delta
174                 else -- between magenta and cyan
175                     H=240.0+60.0*(R-G)/Delta
176             */
177             if(r == maxV)
178                h = db - dg;
179             else if(g == maxV)
180                h = 2 + dr - db;
181             else if(b == maxV)
182                h = 4 + dg - dr;
183             if(h < 0)
184                h += 6;
185          }
186          else
187          {
188             h = 0;
189             s = 0;
190          }
191          this.h = h * Degrees { 60 };
192          this.s = s * 100;
193          this.v = v * 100;
194       }
195
196       get
197       {
198          float deg = (float)(this.h / 60);
199          float h = (deg == 6) ? 0 : deg, s = this.s / 100, v = this.v / 100;
200          int i = (int) h;
201          float f = h - i;
202          float p = v*(1-s);
203          float q = v*(1-(s*f));
204          float t = v*(1-s*(1-f));
205          float r,g,b;
206          switch(i)
207          {
208             case 0: r = v; g = t; b = p; break;
209             case 1: r = q; g = v; b = p; break;
210             case 2: r = p; g = v; b = t; break;
211             case 3: r = p; g = q; b = v; break;
212             case 4: r = t; g = p; b = v; break;
213             case 5: r = v; g = p; b = q; break;
214          }
215          // TODO: Figure out where this is needed
216          r = Max(Min(r, 1),0);
217          g = Max(Min(g, 1),0);
218          b = Max(Min(b, 1),0);
219
220          value.r = r;
221          value.g = g;
222          value.b = b;
223       }
224    }
225 };
226
227 public struct ColorLab
228 {
229    float l,a,b;
230
231    property ColorRGB
232    {
233       set
234       {
235          float r = value.r, g = value.g, b = value.b;
236          float y2;
237
238          r = (float)pow((r + 0.055)/1.055, 2.4);
239          g = (float)pow((g + 0.055)/1.055, 2.4);
240          b = (float)pow((b + 0.055)/1.055, 2.4);
241
242          {
243             float x = r * 0.412453f + g * 0.357580f + b * 0.180423f;
244             float y = r * 0.212671f + g * 0.715160f + b * 0.072169f;
245             float z = r * 0.019334f + g * 0.119193f + b * 0.950227f;
246
247             x /= 0.950456f;
248             y /= 1;
249             z /= 1.088754f;
250
251             x  = (x > 0.008856f) ? (float)pow(x, 1.0f/3) : (7.787f * x + 16/116.0f);
252             y2 = (y > 0.008856f) ? (float)pow(y, 1.0f/3) : (7.787f * y + 16/116.0f);
253             z  = (z > 0.008856f) ? (float)pow(z, 1.0f/3) : (7.787f * z + 16/116.0f);
254
255             if(y > 0.008856)
256                l = 116 * y2 - 16;
257             else
258                l = 903.3f * y;
259             this.a = 500 * (x - y2);
260             this.b = 200 * (y2 - z);
261          }
262       }
263
264       get
265       {
266          float x,y,z,r,g,b, P;
267
268          P = (l + 16)/116;
269
270          if(l > 903.3f * 0.008856f)
271          {
272             y = (l + 16) / 116;
273             y = y*y*y;
274          }
275          else
276             y = l / 903.3f;
277
278          if(y > 0.008856f)
279             P = (l + 16) / 116;
280          else
281             P = (903.3f * y + 16) / 116;
282
283
284          x = a / 500 + P;
285          if(x > 0.206893f)
286             x = x*x*x;
287          else
288             x = (116 * x - 16) / 903.3f;
289
290          z = P - this.b / 200;
291          if(z > 0.206893f)
292             z = z*z*z;
293          else
294             z = (116 * z - 16) / 903.3f;
295
296
297          x *= 0.950456f;
298          y *= 1;
299          z *= 1.088754f;
300
301          r = x * 3.240479f + y * -1.537150f + z *-0.498535f;
302          g = x *-0.969256f + y *  1.875992f + z * 0.041556f;
303          b = x * 0.055648f + y * -0.204043f + z * 1.057311f;
304
305          r = (r > 0.00304f) ? (1.055f * (float)pow(r, 1/2.4) - 0.055f) : (12.92f * r);
306          g = (g > 0.00304f) ? (1.055f * (float)pow(g, 1/2.4) - 0.055f) : (12.92f * g);
307          b = (b > 0.00304f) ? (1.055f * (float)pow(b, 1/2.4) - 0.055f) : (12.92f * b);
308
309          // TODO: Figure out where this is needed
310          r = Max(Min(r, 1),0);
311          g = Max(Min(g, 1),0);
312          b = Max(Min(b, 1),0);
313
314          value.r = r;
315          value.g = g;
316          value.b = b;
317       }
318    }
319 };
320
321 public struct ColorCMYK
322 {
323    float c,m,y,k;
324    property ColorRGB
325    {
326       set
327       {
328          float c = 1 - value.r;
329          float m = 1 - value.g;
330          float y = 1 - value.b;
331          float k = Min(Min(c,m), y);
332          if(k == 1)
333             this.c = this.m = this.y = 0;
334          else
335          {
336             this.c = (c-k)/(1-k) * 100;
337             this.m = (m-k)/(1-k) * 100;
338             this.y = (y-k)/(1-k) * 100;
339          }
340          this.k = k * 100;
341       }
342
343       get
344       {
345          float k = this.k/100;
346          value.r = 1 - ((c / 100) * (1-k) + k);
347          value.g = 1 - ((m / 100) * (1-k) + k);
348          value.b = 1 - ((y / 100) * (1-k) + k);
349
350          // TODO: Figure out where this is needed
351          value.r = Max(Min(value.r, 1),0);
352          value.g = Max(Min(value.g, 1),0);
353          value.b = Max(Min(value.b, 1),0);
354       }
355    }
356 };
357
358 public class Color565 : uint16
359 {
360 public:
361    byte r:5:11;
362    byte g:6:5;
363    byte b:5:0;
364    property Color
365    {
366       set { return Color565 { value.r >> 3, value.g >> 2, value.b >> 3 }; }
367       get { return Color    { r << 3, g << 2, b << 3 }; }
368    }
369 }
370
371 public class Color555 : uint16
372 {
373 public:
374    byte r:5:10;
375    byte g:5:5;
376    byte b:5:0;
377    property Color
378    {
379       set { return Color555 { value.r >> 3, value.g >> 3, value.b >> 3 }; }
380       get { return Color    { r << 3, g << 3, b << 3 }; }
381    }
382 }
383
384 public class Color444 : uint16
385 {
386 public:
387    byte r:4:8;
388    byte g:4:4;
389    byte b:4:0;
390    property Color
391    {
392       set { return Color444 { value.r >> 4, value.g >> 4, value.b >> 4 }; }
393       get { return Color    { r << 4, g << 4, b << 4 }; }
394    }
395 }
396
397 public class ColorAlpha
398 {
399 public:
400    byte a:8:24;
401    Color color:24:0;
402
403    property Color
404    {
405       set { return ColorAlpha { 255, value }; }
406       get { return color; }
407    }
408    /*property ColorRGBA
409    {
410       set { return ColorAlpha { value.a, Color { value.r, value.g, value.b } }; }
411       get { return ColorRGBA { color.r, color.g, color.b, a }; }
412    }*/
413 }
414
415 public class ColorRGBA
416 {
417 public:
418    byte r:8;
419    byte g:8;
420    byte b:8;
421    byte a:8;
422    property ColorAlpha
423    {
424       set { return ColorRGBA { value.color.r, value.color.g, value.color.b, value.a }; }
425       get { return ColorAlpha { a, Color { r, g, b } }; }
426    }
427    property Color
428    {
429       set { return ColorRGBA { value.r, value.g, value.b, 255 }; }
430       get { return Color { r, g, b }; }
431    }
432 }
433
434 public enum DefinedColor : Color
435 {
436    black               = Color {   0,   0,   0 },
437    dimGray             = Color { 105, 105, 105 },
438    gray                = Color { 128, 128, 128 },
439    darkGray            = Color { 169, 169, 165 },
440    silver              = Color { 192, 192, 192 },
441    lightGray           = Color { 211, 211, 211 },
442    gainsboro           = Color { 220, 220, 220 },
443    whiteSmoke          = Color { 245, 245, 245 },
444    white               = Color { 255, 255, 255 },
445    rosyBrown           = Color { 188, 143, 143 },
446    indianRed           = Color { 205,  92,  92 },
447    brown               = Color { 165,  42,  42 },
448    fireBrick           = Color { 178,  34,  34 },
449    lightCoral          = Color { 240, 128, 128 },
450    maroon              = Color { 128,   0,   0 },
451    darkRed             = Color { 139,   0,   0 },
452    red                 = Color { 255,   0,   0 },
453    snow                = Color { 255, 250, 250 },
454    mistyRose           = Color { 255, 228, 225 },
455    salmon              = Color { 250, 128, 114 },
456    tomato              = Color { 255,  99,  71 },
457    darkSalmon          = Color { 233, 150, 122 },
458    coral               = Color { 255, 127,  80 },
459    orangeRed           = Color { 255,  69,   0 },
460    lightSalmon         = Color { 255, 160, 122 },
461    sienna              = Color { 160,  82,  45 },
462    seaShell            = Color { 255, 245, 238 },
463    chocolate           = Color { 210, 105,  30 },
464    saddleBrown         = Color { 139,  69,  19 },
465    sandyBrown          = Color { 244, 164,  96 },
466    peachPuff           = Color { 255, 218, 185 },
467    peru                = Color { 205, 133,  63 },
468    linen               = Color { 250, 240, 230 },
469    bisque              = Color { 255, 228, 196 },
470    darkOrange          = Color { 255, 140,   0 },
471    burlyWood           = Color { 222, 184, 135 },
472    tan                 = Color { 210, 180, 140 },
473    antiqueWhite        = Color { 250, 235, 215 },
474    navajoWhite         = Color { 255, 222, 173 },
475    blanchedAlmond      = Color { 255, 235, 205 },
476    papayaWhip          = Color { 255, 239, 213 },
477    mocassin            = Color { 255, 228, 181 },
478    orange              = Color { 255, 165,   0 },
479    wheat               = Color { 245, 222, 179 },
480    oldLace             = Color { 253, 245, 230 },
481    floralWhite         = Color { 255, 250, 240 },
482    darkGoldenrod       = Color { 184, 134,  11 },
483    goldenrod           = Color { 218, 165,  32 },
484    cornsilk            = Color { 255, 248, 220 },
485    gold                = Color { 255, 215,   0 },
486    khaki               = Color { 240, 230, 140 },
487    lemonChiffon        = Color { 255, 250, 205 },
488    paleGoldenrod       = Color { 238, 232, 170 },
489    darkKhaki           = Color { 189, 183, 107 },
490    beige               = Color { 245, 245, 220 },
491    lightGoldenRodYellow= Color { 250, 250, 210 },
492    olive               = Color { 128, 128,   0 },
493    yellow              = Color { 255, 255,   0 },
494    lightYellow         = Color { 255, 255, 224 },
495    ivory               = Color { 255, 255, 240 },
496    oliveDrab           = Color { 107, 142,  35 },
497    yellowGreen         = Color { 154, 205,  50 },
498    darkOliveGreen      = Color {  85, 107,  47 },
499    greenYellow         = Color { 173, 255,  47 },
500    chartreuse          = Color { 127, 255,   0 },
501    lawnGreen           = Color { 124, 252,   0 },
502    darkSeaGreen        = Color { 143, 188, 139 },
503    forestGreen         = Color {  34, 139,  34 },
504    limeGreen           = Color {  50, 205,  50 },
505    lightGreen          = Color { 144, 238, 144 },
506    paleGreen           = Color { 152, 251, 152 },
507    darkGreen           = Color {   0, 100,   0 },
508    green               = Color {   0, 128,   0 },
509    lime                = Color {   0, 255,   0 },
510    honeyDew            = Color { 240, 255, 240 },
511    seaGreen            = Color {  46, 139,  87 },
512    mediumSeaGreen      = Color {  60, 179, 113 },
513    springGreen         = Color {   0, 255, 127 },
514    mintCream           = Color { 245, 255, 250 },
515    mediumSpringGreen   = Color {   0, 250, 154 },
516    mediumAquaMarine    = Color { 102, 205, 170 },
517    aquamarine          = Color { 127, 255, 212 },
518    turquoise           = Color {  64, 224, 208 },
519    lightSeaGreen       = Color {  32, 178, 170 },
520    mediumTurquoise     = Color {  72, 209, 204 },
521    darkSlateGray       = Color {  47,  79,  79 },
522    paleTurquoise       = Color { 175, 238, 238 },
523    teal                = Color {   0, 128, 128 },
524    darkCyan            = Color {   0, 139, 139 },
525    aqua                = Color {   0, 255, 255 },
526    cyan                = Color {   0, 255, 255 },
527    lightCyan           = Color { 224, 255, 255 },
528    azure               = Color { 240, 255, 255 },
529    darkTurquoise       = Color {   0, 206, 209 },
530    cadetBlue           = Color {  95, 158, 160 },
531    powderBlue          = Color { 176, 224, 230 },
532    lightBlue           = Color { 173, 216, 230 },
533    deepSkyBlue         = Color {   0, 191, 255 },
534    skyBlue             = Color { 135, 206, 235 },
535    lightSkyBlue        = Color { 135, 206, 250 },
536    steelBlue           = Color {  70, 130, 180 },
537    aliceBlue           = Color { 240, 248, 255 },
538    dodgerBlue          = Color {  30, 144, 255 },
539    slateGray           = Color { 112, 128, 144 },
540    lightSlateGray      = Color { 119, 136, 153 },
541    lightSteelBlue      = Color { 176, 196, 222 },
542    cornflowerBlue      = Color { 100, 149, 237 },
543    royalBlue           = Color {  65, 105, 225 },
544    midnightBlue        = Color {  25,  25, 112 },
545    lavender            = Color { 230, 230, 250 },
546    navy                = Color {   0,   0, 128 },
547    darkBlue            = Color {   0,   0, 139 },
548    mediumBlue          = Color {   0,   0, 205 },
549    blue                = Color {   0,   0, 255 },
550    ghostWhite          = Color { 248, 248, 255 },
551    slateBlue           = Color { 106,  90, 205 },
552    darkSlateBlue       = Color {  72,  61, 139 },
553    mediumSlateBlue     = Color { 123, 104, 238 },
554    mediumPurple        = Color { 147, 112, 219 },
555    blueViolet          = Color { 138,  43, 226 },
556    indigo              = Color {  75,   0, 130 },
557    darkOrchid          = Color { 153,  50, 204 },
558    darkViolet          = Color { 148,   0, 211 },
559    mediumOrchid        = Color { 186,  85, 211 },
560    thistle             = Color { 216, 191, 216 },
561    plum                = Color { 221, 160, 221 },
562    violet              = Color { 238, 130, 238 },
563    purple              = Color { 128,   0, 128 },
564    darkMagenta         = Color { 139,   0, 139 },
565    magenta             = Color { 255,   0, 255 },
566    fuschia             = Color { 255,   0, 255 },
567    orchid              = Color { 218, 112, 214 },
568    mediumVioletRed     = Color { 199,  21, 133 },
569    deepPink            = Color { 255,  20, 147 },
570    hotPink             = Color { 255, 155, 180 },
571    lavenderBlush       = Color { 255, 240, 245 },
572    paleVioletRed       = Color { 219, 112, 147 },
573    crimson             = Color { 220,  20,  60 },
574    pink                = Color { 255, 192, 203 },
575    lightPink           = Color { 255, 182, 193 }
576 };
577
578 // TODO: We really should improve on this, only formColor has been used so far
579 public enum SystemColor : Color
580 {
581    // activeBorder         = Color { 212, 208, 200 },
582    formColor            = Color { 229, 234, 245 },
583    activeBorder         = Color { 229, 234, 245 },
584    control              = Color { 212, 208, 200 },
585    controlLight         = Color { 212, 208, 200 },
586    inactiveBorder       = Color { 212, 208, 200 },
587    inactiveCaptionText  = Color { 212, 208, 200 },
588    menu                 = Color { 212, 208, 200 },
589    scrollBar            = Color { 212, 208, 200 }
590 };
591
592 private class ColorValue : Color
593 {
594    void OnDisplay(Surface surface, int x, int y, int width, char * fieldData, Alignment alignment, DataDisplayFlags displayFlags)
595    {
596       // surface.WriteTextDots(alignment, x + 24, y + 1, width - 24, string, strlen(string));
597       surface.SetBackground(this);
598       surface.Area(x, y + 4, x+19, y+11);
599
600       surface.SetForeground(black);
601       surface.Rectangle(x-1, y + 3, x + 20, y + 12);
602    }
603 }
604
605 // TODO: ColorSelected was declared as non static
606 /*static */class ColorDropBox : DropBox
607 {
608    ListBox listBox;
609    Color color;
610    Window control;
611    borderStyle = 0;
612
613    DataField sysColorField { dataType = "ColorValue", width = 20 };
614    DataField sysColorName { };
615    DataField definedColorField { dataType = "ColorValue", width = 20 };
616    DataField definedColorName { };
617
618    ColorDropBox()
619    {
620       system.AddField(sysColorField);
621       system.AddField(sysColorName);
622       defined.AddField(definedColorField);
623       defined.AddField(definedColorName);
624    }
625
626    Window pullDown
627    {
628       master = this, interim = true, autoCreate = false, minSize = { 204, 222 },
629       background = formColor, borderStyle = contour|bevel;
630
631       bool OnKeyDown(Key key, unichar ch)
632       {
633          ColorDropBox colorDropBox = (ColorDropBox)master;
634          if((SmartKey)key == enter)
635          {
636             if(!colorDropBox.ColorSelected(colorDropBox.listBox, colorDropBox.listBox.currentRow, 0))
637                return false;
638          }
639          if(key == escape)
640          {
641             return colorDropBox.OnKeyDown(key, ch);
642          }
643          return true;
644       }
645    };
646
647    bool ColorSelected(ListBox listBox, DataRow row, Modifiers mods)
648    {
649       Color color = row ? row.GetData(null) : black;
650
651       incref this;
652       ((DataBox)parent).SetData(&color, false);
653
654       this.color = color;
655
656       {
657          char tempString[1024] = "";
658          bool needClass = false;
659          char * string = color.OnGetString(tempString, null, &needClass);
660          contents = string;
661       }
662       OnKeyDown(escape, 0);
663       Deactivate();
664       delete this;
665
666       //OnKeyDown(escape, 0);
667       //master.OnKeyDown(escape, 0);
668
669       return true;
670    }
671
672    ListBox defined
673    {
674       master = this, parent = pullDown,
675       freeSelect = true,
676       hasVertScroll = true,
677       anchor = Anchor { left = 0, top = 16, right = 0, bottom = 0 },
678       NotifySelect = ColorSelected
679    };
680    ListBox system
681    {
682       master = this, parent = pullDown,
683       freeSelect = true,
684       hasVertScroll = true,
685       anchor = Anchor { left = 0, top = 16, right = 0, bottom = 0 },
686       NotifySelect = ColorSelected
687    };
688
689    ColorPicker dialog
690    {
691       text = $"Select Color",
692       master = this,
693       autoCreate = false
694    };
695
696    Button button
697    {
698       master = this, parent = pullDown,
699       text = $"Custom",
700       size.w = 68,
701       position = Point { 0, 0 },
702       bevelOver = true,
703       inactive = true,
704       hotKey = altC;
705       // isRadio = true, bitmap = null;
706
707       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
708       {
709          dialog.color = color;
710
711          OnKeyDown(escape, 0);
712          Deactivate();
713
714          //OnKeyDown(Escape, 0);
715          //master.OnKeyDown(Escape, 0);
716
717          incref this;
718          if(dialog.Modal() == ok)
719          {
720             color = dialog.color;
721             ((DataBox)master).SetData(&color, false);
722             {
723                char tempString[1024] = "";
724                bool needClass = false;
725                char * string = color.OnGetString(tempString, null, &needClass);
726                contents = string;
727             }
728          }
729          delete this;
730          return true;
731       }
732    };
733    Button definedButton
734    {
735       master = this, parent = pullDown,
736       text = $"Defined",
737       hotKey = altD,
738       size.w = 68,
739       position = Point { 68, 0 },
740       isRadio = true,
741       bevelOver = true,
742       inactive = true,
743       bitmap = null;
744
745       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
746       {
747          system.visible = false;
748          defined.visible = true;
749          listBox = defined;
750          return true;
751       }
752    };
753    Button systemButton
754    {
755       master = this, parent = pullDown,
756       text = $"System",
757       hotKey = altS,
758       size.w = 68,
759       position = Point { 136, 0 },
760       isRadio = true,
761       bevelOver = true,
762       inactive = true,
763       bitmap = null;
764
765       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
766       {
767          defined.visible = false;
768          system.visible = true;
769          listBox = system;
770          return true;
771       }
772    };
773
774    Window OnDropDown()
775    {
776       char tempString[256];
777       pullDown.size.w = size.w + 24;
778
779       pullDown.Create();
780
781       {
782          NamedLink item;
783          bool found = false;
784          DataRow currentRow = null;
785
786          defined.Clear();
787          for(item = ((EnumClassData)class(DefinedColor).data).values.first; item; item = item.next)
788          {
789             DataRow row = defined.AddRow();
790             row.SetData(definedColorField, (Color)(uint)item.data);
791             strcpy(tempString, item.name);
792             tempString[0] = (char)toupper(tempString[0]);
793             row.SetData(definedColorName, tempString);
794             // TOCHECK: A uint cast is necessary here, the void * was causing ColorRGB conversion to be called
795             if(!found && (Color)(uint)item.data == color)
796             {
797                currentRow = row;
798                found = true;
799             }
800          }
801          if(currentRow)
802             defined.currentRow = currentRow;
803       }
804       {
805          bool found = false;
806          NamedLink item;
807          DataRow currentRow = null;
808
809          system.Clear();
810          for(item = ((EnumClassData)class(SystemColor).data).values.first; item; item = item.next)
811          {
812             DataRow row = system.AddRow();
813             row.SetData(sysColorField, (Color)(uint)item.data);
814             strcpy(tempString, item.name);
815             tempString[0] = (char)toupper(tempString[0]);
816             row.SetData(sysColorName, tempString);
817
818             // TOCHECK: A uint cast is necessary here, the void * was causing ColorRGB conversion to be called
819             if(!found && (Color)(uint)item.data == color)
820             {
821                currentRow = row;
822                found = true;
823             }
824          }
825          if(currentRow)
826             system.currentRow = currentRow;
827
828          if(found)
829          {
830             defined.visible = false;
831             system.visible = true;
832             systemButton.checked = true;
833             listBox = system;
834          }
835          else
836          {
837             system.visible = false;
838             defined.visible = true;
839             definedButton.checked = true;
840             listBox = defined;
841          }
842       }
843       return pullDown;
844    }
845
846    void OnCloseDropDown(Window pullDown)
847    {
848       // TOFIX: Patch for update bug
849       master.Update(null);
850       pullDown.Destroy(0);
851    }
852
853    bool DataBox::NotifyTextEntry(ColorDropBox colorDropBox, char * string, bool save)
854    {
855       if(save)
856       {
857          Color color = 0;
858          if(color.OnGetDataFromString(string))
859             SetData(&color, false);
860       }
861       else
862       {
863          char tempString[1024] = "";
864          bool needClass = false;
865          char * string = colorDropBox.color.OnGetString(tempString,null, &needClass);
866          colorDropBox.contents = string;
867       }
868       return true;
869    }
870 }