|
1
|
/* |
|
2
|
** Copyright (c) 2007 D. Richard Hipp |
|
3
|
** |
|
4
|
** This program is free software; you can redistribute it and/or |
|
5
|
** modify it under the terms of the Simplified BSD License (also |
|
6
|
** known as the "2-Clause License" or "FreeBSD License".) |
|
7
|
|
|
8
|
** This program is distributed in the hope that it will be useful, |
|
9
|
** but without any warranty; without even the implied warranty of |
|
10
|
** merchantability or fitness for a particular purpose. |
|
11
|
** |
|
12
|
** Author contact information: |
|
13
|
** [email protected] |
|
14
|
** http://www.hwaci.com/drh/ |
|
15
|
** |
|
16
|
******************************************************************************* |
|
17
|
** |
|
18
|
** This file contains code used to select colors based on branch and |
|
19
|
** user names. |
|
20
|
** |
|
21
|
*/ |
|
22
|
#include "config.h" |
|
23
|
#include <string.h> |
|
24
|
#include "color.h" |
|
25
|
|
|
26
|
/* |
|
27
|
** 140 standard CSS color names and their corresponding RGB values, |
|
28
|
** in alphabetical order by name so that we can do a binary search |
|
29
|
** for lookup. |
|
30
|
*/ |
|
31
|
static const struct CssColors { |
|
32
|
const char *zName; /* CSS Color name, lower case */ |
|
33
|
unsigned int iRGB; /* Corresponding RGB value */ |
|
34
|
} aCssColors[] = { |
|
35
|
{ "aliceblue", 0xf0f8ff }, |
|
36
|
{ "antiquewhite", 0xfaebd7 }, |
|
37
|
{ "aqua", 0x00ffff }, |
|
38
|
{ "aquamarine", 0x7fffd4 }, |
|
39
|
{ "azure", 0xf0ffff }, |
|
40
|
{ "beige", 0xf5f5dc }, |
|
41
|
{ "bisque", 0xffe4c4 }, |
|
42
|
{ "black", 0x000000 }, |
|
43
|
{ "blanchedalmond", 0xffebcd }, |
|
44
|
{ "blue", 0x0000ff }, |
|
45
|
{ "blueviolet", 0x8a2be2 }, |
|
46
|
{ "brown", 0xa52a2a }, |
|
47
|
{ "burlywood", 0xdeb887 }, |
|
48
|
{ "cadetblue", 0x5f9ea0 }, |
|
49
|
{ "chartreuse", 0x7fff00 }, |
|
50
|
{ "chocolate", 0xd2691e }, |
|
51
|
{ "coral", 0xff7f50 }, |
|
52
|
{ "cornflowerblue", 0x6495ed }, |
|
53
|
{ "cornsilk", 0xfff8dc }, |
|
54
|
{ "crimson", 0xdc143c }, |
|
55
|
{ "cyan", 0x00ffff }, |
|
56
|
{ "darkblue", 0x00008b }, |
|
57
|
{ "darkcyan", 0x008b8b }, |
|
58
|
{ "darkgoldenrod", 0xb8860b }, |
|
59
|
{ "darkgray", 0xa9a9a9 }, |
|
60
|
{ "darkgreen", 0x006400 }, |
|
61
|
{ "darkkhaki", 0xbdb76b }, |
|
62
|
{ "darkmagenta", 0x8b008b }, |
|
63
|
{ "darkolivegreen", 0x556b2f }, |
|
64
|
{ "darkorange", 0xff8c00 }, |
|
65
|
{ "darkorchid", 0x9932cc }, |
|
66
|
{ "darkred", 0x8b0000 }, |
|
67
|
{ "darksalmon", 0xe9967a }, |
|
68
|
{ "darkseagreen", 0x8fbc8f }, |
|
69
|
{ "darkslateblue", 0x483d8b }, |
|
70
|
{ "darkslategray", 0x2f4f4f }, |
|
71
|
{ "darkturquoise", 0x00ced1 }, |
|
72
|
{ "darkviolet", 0x9400d3 }, |
|
73
|
{ "deeppink", 0xff1493 }, |
|
74
|
{ "deepskyblue", 0x00bfff }, |
|
75
|
{ "dimgray", 0x696969 }, |
|
76
|
{ "dodgerblue", 0x1e90ff }, |
|
77
|
{ "firebrick", 0xb22222 }, |
|
78
|
{ "floralwhite", 0xfffaf0 }, |
|
79
|
{ "forestgreen", 0x228b22 }, |
|
80
|
{ "fuchsia", 0xff00ff }, |
|
81
|
{ "gainsboro", 0xdcdcdc }, |
|
82
|
{ "ghostwhite", 0xf8f8ff }, |
|
83
|
{ "gold", 0xffd700 }, |
|
84
|
{ "goldenrod", 0xdaa520 }, |
|
85
|
{ "gray", 0x808080 }, |
|
86
|
{ "green", 0x008000 }, |
|
87
|
{ "greenyellow", 0xadff2f }, |
|
88
|
{ "honeydew", 0xf0fff0 }, |
|
89
|
{ "hotpink", 0xff69b4 }, |
|
90
|
{ "indianred", 0xcd5c5c }, |
|
91
|
{ "indigo", 0x4b0082 }, |
|
92
|
{ "ivory", 0xfffff0 }, |
|
93
|
{ "khaki", 0xf0e68c }, |
|
94
|
{ "lavender", 0xe6e6fa }, |
|
95
|
{ "lavenderblush", 0xfff0f5 }, |
|
96
|
{ "lawngreen", 0x7cfc00 }, |
|
97
|
{ "lemonchiffon", 0xfffacd }, |
|
98
|
{ "lightblue", 0xadd8e6 }, |
|
99
|
{ "lightcoral", 0xf08080 }, |
|
100
|
{ "lightcyan", 0xe0ffff }, |
|
101
|
{ "lightgoldenrodyellow", 0xfafad2 }, |
|
102
|
{ "lightgrey", 0xd3d3d3 }, |
|
103
|
{ "lightgreen", 0x90ee90 }, |
|
104
|
{ "lightpink", 0xffb6c1 }, |
|
105
|
{ "lightsalmon", 0xffa07a }, |
|
106
|
{ "lightseagreen", 0x20b2aa }, |
|
107
|
{ "lightskyblue", 0x87cefa }, |
|
108
|
{ "lightslategray", 0x778899 }, |
|
109
|
{ "lightsteelblue", 0xb0c4de }, |
|
110
|
{ "lightyellow", 0xffffe0 }, |
|
111
|
{ "lime", 0x00ff00 }, |
|
112
|
{ "limegreen", 0x32cd32 }, |
|
113
|
{ "linen", 0xfaf0e6 }, |
|
114
|
{ "magenta", 0xff00ff }, |
|
115
|
{ "maroon", 0x800000 }, |
|
116
|
{ "mediumaquamarine", 0x66cdaa }, |
|
117
|
{ "mediumblue", 0x0000cd }, |
|
118
|
{ "mediumorchid", 0xba55d3 }, |
|
119
|
{ "mediumpurple", 0x9370d8 }, |
|
120
|
{ "mediumseagreen", 0x3cb371 }, |
|
121
|
{ "mediumslateblue", 0x7b68ee }, |
|
122
|
{ "mediumspringgreen", 0x00fa9a }, |
|
123
|
{ "mediumturquoise", 0x48d1cc }, |
|
124
|
{ "mediumvioletred", 0xc71585 }, |
|
125
|
{ "midnightblue", 0x191970 }, |
|
126
|
{ "mintcream", 0xf5fffa }, |
|
127
|
{ "mistyrose", 0xffe4e1 }, |
|
128
|
{ "moccasin", 0xffe4b5 }, |
|
129
|
{ "navajowhite", 0xffdead }, |
|
130
|
{ "navy", 0x000080 }, |
|
131
|
{ "oldlace", 0xfdf5e6 }, |
|
132
|
{ "olive", 0x808000 }, |
|
133
|
{ "olivedrab", 0x6b8e23 }, |
|
134
|
{ "orange", 0xffa500 }, |
|
135
|
{ "orangered", 0xff4500 }, |
|
136
|
{ "orchid", 0xda70d6 }, |
|
137
|
{ "palegoldenrod", 0xeee8aa }, |
|
138
|
{ "palegreen", 0x98fb98 }, |
|
139
|
{ "paleturquoise", 0xafeeee }, |
|
140
|
{ "palevioletred", 0xd87093 }, |
|
141
|
{ "papayawhip", 0xffefd5 }, |
|
142
|
{ "peachpuff", 0xffdab9 }, |
|
143
|
{ "peru", 0xcd853f }, |
|
144
|
{ "pink", 0xffc0cb }, |
|
145
|
{ "plum", 0xdda0dd }, |
|
146
|
{ "powderblue", 0xb0e0e6 }, |
|
147
|
{ "purple", 0x800080 }, |
|
148
|
{ "red", 0xff0000 }, |
|
149
|
{ "rosybrown", 0xbc8f8f }, |
|
150
|
{ "royalblue", 0x4169e1 }, |
|
151
|
{ "saddlebrown", 0x8b4513 }, |
|
152
|
{ "salmon", 0xfa8072 }, |
|
153
|
{ "sandybrown", 0xf4a460 }, |
|
154
|
{ "seagreen", 0x2e8b57 }, |
|
155
|
{ "seashell", 0xfff5ee }, |
|
156
|
{ "sienna", 0xa0522d }, |
|
157
|
{ "silver", 0xc0c0c0 }, |
|
158
|
{ "skyblue", 0x87ceeb }, |
|
159
|
{ "slateblue", 0x6a5acd }, |
|
160
|
{ "slategray", 0x708090 }, |
|
161
|
{ "snow", 0xfffafa }, |
|
162
|
{ "springgreen", 0x00ff7f }, |
|
163
|
{ "steelblue", 0x4682b4 }, |
|
164
|
{ "tan", 0xd2b48c }, |
|
165
|
{ "teal", 0x008080 }, |
|
166
|
{ "thistle", 0xd8bfd8 }, |
|
167
|
{ "tomato", 0xff6347 }, |
|
168
|
{ "turquoise", 0x40e0d0 }, |
|
169
|
{ "violet", 0xee82ee }, |
|
170
|
{ "wheat", 0xf5deb3 }, |
|
171
|
{ "white", 0xffffff }, |
|
172
|
{ "whitesmoke", 0xf5f5f5 }, |
|
173
|
{ "yellow", 0xffff00 }, |
|
174
|
{ "yellowgreen", 0x9acd32 }, |
|
175
|
}; |
|
176
|
|
|
177
|
/* |
|
178
|
** Attempt to translate a CSS color name into an integer that |
|
179
|
** represents the equivalent RGB value. Ignore alpha if provided. |
|
180
|
** If the name cannot be translated, return -1. |
|
181
|
*/ |
|
182
|
int color_name_to_rgb(const char *zName){ |
|
183
|
if( zName==0 || zName[0]==0 ) return -1; |
|
184
|
if( zName[0]=='#' ){ |
|
185
|
int i, v = 0; |
|
186
|
for(i=1; i<=6 && fossil_isxdigit(zName[i]); i++){ |
|
187
|
v = v*16 + fossil_hexvalue(zName[i]); |
|
188
|
} |
|
189
|
if( i==4 ){ |
|
190
|
v = fossil_hexvalue(zName[1])*0x110000 + |
|
191
|
fossil_hexvalue(zName[2])*0x1100 + |
|
192
|
fossil_hexvalue(zName[3])*0x11; |
|
193
|
return v; |
|
194
|
} |
|
195
|
if( i==7 ){ |
|
196
|
return v; |
|
197
|
} |
|
198
|
return -1; |
|
199
|
}else{ |
|
200
|
int iMin = 0; |
|
201
|
int iMax = count(aCssColors)-1; |
|
202
|
while( iMin<=iMax ){ |
|
203
|
int iMid = (iMin+iMax)/2; |
|
204
|
int c = sqlite3_stricmp(aCssColors[iMid].zName, zName); |
|
205
|
if( c==0 ) return aCssColors[iMid].iRGB; |
|
206
|
if( c<0 ){ |
|
207
|
iMin = iMid+1; |
|
208
|
}else{ |
|
209
|
iMax = iMid-1; |
|
210
|
} |
|
211
|
} |
|
212
|
return -1; |
|
213
|
} |
|
214
|
} |
|
215
|
|
|
216
|
/* |
|
217
|
** SETTING: raw-bgcolor boolean default=off |
|
218
|
** |
|
219
|
** Fossil usually tries to adjust user-specified background colors |
|
220
|
** for check-ins so that the text is readable and so that the color |
|
221
|
** is not too garish. This setting disables that filter. When |
|
222
|
** this setting is on, the user-selected background colors are shown |
|
223
|
** exactly as requested. |
|
224
|
*/ |
|
225
|
|
|
226
|
/* |
|
227
|
** Shift a color provided by the user so that it is suitable |
|
228
|
** for use as a background color in the current skin. |
|
229
|
** |
|
230
|
** The return value is a #HHHHHH color name contained in |
|
231
|
** static space that is overwritten on the next call. |
|
232
|
** |
|
233
|
** If we cannot make sense of the background color recommendation |
|
234
|
** that is the input, then return NULL. |
|
235
|
** |
|
236
|
** The iFgClr parameter is normally 0. But for testing purposes, set |
|
237
|
** it to 1 for a black foregrounds and 2 for a white foreground. |
|
238
|
*/ |
|
239
|
const char *reasonable_bg_color(const char *zRequested, int iFgClr){ |
|
240
|
int iRGB = color_name_to_rgb(zRequested); |
|
241
|
int r, g, b; /* RGB components of requested color */ |
|
242
|
static int systemFg = 0; /* 1==black-foreground 2==white-foreground */ |
|
243
|
int fg; /* Foreground color to actually use */ |
|
244
|
static char zColor[10]; /* Return value */ |
|
245
|
|
|
246
|
if( iFgClr ){ |
|
247
|
fg = iFgClr; |
|
248
|
}else if( systemFg==0 ){ |
|
249
|
if( db_get_boolean("raw-bgcolor",0) ){ |
|
250
|
fg = systemFg = 3; |
|
251
|
}else{ |
|
252
|
fg = systemFg = skin_detail_boolean("white-foreground") ? 2 : 1; |
|
253
|
} |
|
254
|
}else{ |
|
255
|
fg = systemFg; |
|
256
|
} |
|
257
|
if( fg>=3 ) return zRequested; |
|
258
|
|
|
259
|
if( iRGB<0 ) return 0; |
|
260
|
r = (iRGB>>16) & 0xff; |
|
261
|
g = (iRGB>>8) & 0xff; |
|
262
|
b = iRGB & 0xff; |
|
263
|
if( fg==1 ){ |
|
264
|
/* Dark text on a light background. Adjust so that |
|
265
|
** no color component is less than 255-K, resulting in |
|
266
|
** a pastel background color. Color adjustment is quadratic |
|
267
|
** so that colors that are further out of range have a greater |
|
268
|
** adjustment. */ |
|
269
|
const int K = 79; |
|
270
|
int k, x, m; |
|
271
|
m = r<g ? r : g; |
|
272
|
if( m>b ) m = b; |
|
273
|
k = (m*m)/255 + K; |
|
274
|
x = 255 - k; |
|
275
|
r = (k*r)/255 + x; |
|
276
|
g = (k*g)/255 + x; |
|
277
|
b = (k*b)/255 + x; |
|
278
|
}else{ |
|
279
|
/* Light text on a dark background. Adjust so that |
|
280
|
** no color component is greater than K, resulting in |
|
281
|
** a low-intensity, low-saturation background color. |
|
282
|
** The color adjustment is quadratic so that colors that |
|
283
|
** are further out of range have a greater adjustment. */ |
|
284
|
const int K = 112; |
|
285
|
int k, m; |
|
286
|
m = r>g ? r : g; |
|
287
|
if( m<b ) m = b; |
|
288
|
k = 255 - (255-K)*(m*m)/65025; |
|
289
|
r = (k*r)/255; |
|
290
|
g = (k*g)/255; |
|
291
|
b = (k*b)/255; |
|
292
|
} |
|
293
|
sqlite3_snprintf(8, zColor, "#%02x%02x%02x", r,g,b); |
|
294
|
return zColor; |
|
295
|
} |
|
296
|
|
|
297
|
/* |
|
298
|
** Compute a hash on a branch or user name |
|
299
|
*/ |
|
300
|
static unsigned int hash_of_name(const char *z){ |
|
301
|
unsigned int h = 0; |
|
302
|
int i; |
|
303
|
for(i=0; z[i]; i++ ){ |
|
304
|
h = (h<<11) ^ (h<<1) ^ (h>>3) ^ z[i]; |
|
305
|
} |
|
306
|
return h; |
|
307
|
} |
|
308
|
|
|
309
|
/* |
|
310
|
** Hash a string and use the hash to determine a background color. |
|
311
|
** |
|
312
|
** This value returned is in static space and is overwritten with |
|
313
|
** each subsequent call. |
|
314
|
*/ |
|
315
|
char *hash_color(const char *z){ |
|
316
|
unsigned int h = 0; /* Hash on the branch name */ |
|
317
|
int r, g, b; /* Values for red, green, and blue */ |
|
318
|
int h1, h2, h3, h4; /* Elements of the hash value */ |
|
319
|
int mx, mn; /* Components of HSV */ |
|
320
|
static char zColor[10]; /* The resulting color */ |
|
321
|
static int ix[3] = {0,0}; /* Color chooser parameters */ |
|
322
|
|
|
323
|
if( ix[0]==0 ){ |
|
324
|
if( skin_detail_boolean("white-foreground") ){ |
|
325
|
ix[0] = 0x50; |
|
326
|
ix[1] = 0x20; |
|
327
|
}else{ |
|
328
|
ix[0] = 0xf8; |
|
329
|
ix[1] = 0x20; |
|
330
|
} |
|
331
|
} |
|
332
|
h = hash_of_name(z); |
|
333
|
h1 = h % 6; h /= 6; |
|
334
|
h3 = h % 10; h /= 10; |
|
335
|
h4 = h % 10; h /= 10; |
|
336
|
mx = ix[0] - h3; |
|
337
|
mn = mx - h4 - ix[1]; |
|
338
|
h2 = (h%(mx - mn)) + mn; |
|
339
|
switch( h1 ){ |
|
340
|
case 0: r = mx; g = h2, b = mn; break; |
|
341
|
case 1: r = h2; g = mx, b = mn; break; |
|
342
|
case 2: r = mn; g = mx, b = h2; break; |
|
343
|
case 3: r = mn; g = h2, b = mx; break; |
|
344
|
case 4: r = h2; g = mn, b = mx; break; |
|
345
|
default: r = mx; g = mn, b = h2; break; |
|
346
|
} |
|
347
|
sqlite3_snprintf(8, zColor, "#%02x%02x%02x", r,g,b); |
|
348
|
return zColor; |
|
349
|
} |
|
350
|
|
|
351
|
/* |
|
352
|
** Determine a color for users based on their login string. |
|
353
|
** |
|
354
|
** SETTING: user-color-map width=40 block-text |
|
355
|
** |
|
356
|
** The user-color-map setting can be used to override user color choices. |
|
357
|
** The setting is a list of space-separated words pairs. The first word |
|
358
|
** of each pair is a login name. The second word is an alternative name |
|
359
|
** used by the color chooser algorithm. |
|
360
|
** |
|
361
|
** This list is intended to be relatively short. The idea is to only use |
|
362
|
** this map to resolve color collisions between common users. |
|
363
|
** |
|
364
|
** Visit /hash-color-test?rand for a list of suggested names for the |
|
365
|
** second word of each pair in the list. |
|
366
|
*/ |
|
367
|
char *user_color(const char *zLogin){ |
|
368
|
static int once = 0; |
|
369
|
static int nMap = 0; |
|
370
|
static char **azMap = 0; |
|
371
|
static int *anMap = 0; |
|
372
|
int i; |
|
373
|
if( !once ){ |
|
374
|
char *zMap = (char*)db_get("user-color-map",0); |
|
375
|
once = 1; |
|
376
|
if( zMap && zMap[0] ){ |
|
377
|
if( !g.interp ) Th_FossilInit(0); |
|
378
|
Th_SplitList(g.interp, zMap, (int)strlen(zMap), |
|
379
|
&azMap, &anMap, &nMap); |
|
380
|
for(i=0; i<nMap; i++) azMap[i][anMap[i]] = 0; |
|
381
|
} |
|
382
|
} |
|
383
|
for(i=0; i<nMap-1; i+=2){ |
|
384
|
if( strcmp(zLogin, azMap[i])==0 ) return hash_color(azMap[i+1]); |
|
385
|
} |
|
386
|
return hash_color(zLogin); |
|
387
|
} |
|
388
|
|
|
389
|
/* |
|
390
|
** COMMAND: test-hash-color |
|
391
|
** |
|
392
|
** Usage: %fossil test-hash-color TAG ... |
|
393
|
** |
|
394
|
** Print out the color names associated with each tag. Used for |
|
395
|
** testing the hash_color() function. |
|
396
|
*/ |
|
397
|
void test_hash_color(void){ |
|
398
|
int i; |
|
399
|
for(i=2; i<g.argc; i++){ |
|
400
|
fossil_print("%20s: %s\n", g.argv[i], hash_color(g.argv[i])); |
|
401
|
} |
|
402
|
} |
|
403
|
|
|
404
|
/* |
|
405
|
** WEBPAGE: hash-color-test |
|
406
|
** |
|
407
|
** Print out the color names associated with each tag. Used for |
|
408
|
** testing the hash_color() function. |
|
409
|
*/ |
|
410
|
void test_hash_color_page(void){ |
|
411
|
const char *zBr; |
|
412
|
char zNm[10]; |
|
413
|
int i, cnt; |
|
414
|
login_check_credentials(); |
|
415
|
if( P("rand")!=0 ){ |
|
416
|
int j; |
|
417
|
for(i=0; i<10; i++){ |
|
418
|
sqlite3_uint64 u; |
|
419
|
char zClr[10]; |
|
420
|
sqlite3_randomness(sizeof(u), &u); |
|
421
|
cnt = 3+(u%2); |
|
422
|
u /= 2; |
|
423
|
for(j=0; j<cnt; j++){ |
|
424
|
zClr[j] = 'a' + (u%26); |
|
425
|
u /= 26; |
|
426
|
} |
|
427
|
zClr[j] = 0; |
|
428
|
sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i); |
|
429
|
cgi_replace_parameter(fossil_strdup(zNm), fossil_strdup(zClr)); |
|
430
|
} |
|
431
|
} |
|
432
|
style_set_current_feature("test"); |
|
433
|
style_header("Hash Color Test"); |
|
434
|
for(i=cnt=0; i<10; i++){ |
|
435
|
sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i); |
|
436
|
zBr = P(zNm); |
|
437
|
if( zBr && zBr[0] ){ |
|
438
|
@ <p style='border:1px solid;background-color:%s(hash_color(zBr));'> |
|
439
|
@ %h(zBr) - hash 0x%x(hash_of_name(zBr)) - color %s(hash_color(zBr)) - |
|
440
|
@ Omnes nos quasi oves erravimus unusquisque in viam |
|
441
|
@ suam declinavit.</p> |
|
442
|
cnt++; |
|
443
|
} |
|
444
|
} |
|
445
|
if( cnt ){ |
|
446
|
@ <hr> |
|
447
|
} |
|
448
|
@ <form method="POST"> |
|
449
|
@ <p>Enter candidate branch names below and see them displayed in their |
|
450
|
@ default background colors above.</p> |
|
451
|
for(i=0; i<10; i++){ |
|
452
|
sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i); |
|
453
|
zBr = P(zNm); |
|
454
|
@ <input type="text" size="30" name='%s(zNm)' value='%h(PD(zNm,""))'><br> |
|
455
|
} |
|
456
|
@ <input type="submit" value="Submit"> |
|
457
|
@ <input type="submit" name="rand" value="Random"> |
|
458
|
@ </form> |
|
459
|
style_finish_page(); |
|
460
|
} |
|
461
|
|
|
462
|
/* |
|
463
|
** WEBPAGE: test-bgcolor |
|
464
|
** |
|
465
|
** Show how user-specified background colors will be rendered |
|
466
|
** using the reasonable_bg_color() algorithm. |
|
467
|
*/ |
|
468
|
void test_bgcolor_page(void){ |
|
469
|
const char *zReq; /* Requested color name */ |
|
470
|
const char *zBG; /* Actual color provided */ |
|
471
|
const char *zBg1; |
|
472
|
char zNm[10]; |
|
473
|
static const char *azDflt[] = { |
|
474
|
"red", "orange", "yellow", "green", "blue", "indigo", "violet", |
|
475
|
"tan", "brown", "gray", |
|
476
|
}; |
|
477
|
const int N = count(azDflt); |
|
478
|
int i, cnt, iClr, r, g, b; |
|
479
|
char *zFg; |
|
480
|
login_check_credentials(); |
|
481
|
style_set_current_feature("test"); |
|
482
|
style_header("Background Color Test"); |
|
483
|
for(i=cnt=0; i<N; i++){ |
|
484
|
sqlite3_snprintf(sizeof(zNm),zNm,"b%c",'a'+i); |
|
485
|
zReq = PD(zNm,azDflt[i]); |
|
486
|
if( zReq==0 || zReq[0]==0 ) continue; |
|
487
|
if( cnt==0 ){ |
|
488
|
@ <table border="1" cellspacing="0" cellpadding="10"> |
|
489
|
@ <tr> |
|
490
|
@ <th>Requested Background |
|
491
|
@ <th>Light mode |
|
492
|
@ <th>Dark mode |
|
493
|
@ </tr> |
|
494
|
} |
|
495
|
cnt++; |
|
496
|
zBG = reasonable_bg_color(zReq, 0); |
|
497
|
if( zBG==0 ){ |
|
498
|
@ <tr><td colspan="3" align="center">\ |
|
499
|
@ "%h(zReq)" is not a recognized color name</td></tr> |
|
500
|
continue; |
|
501
|
} |
|
502
|
iClr = color_name_to_rgb(zReq); |
|
503
|
r = (iClr>>16) & 0xff; |
|
504
|
g = (iClr>>8) & 0xff; |
|
505
|
b = iClr & 0xff; |
|
506
|
if( 3*r + 7*g + b > 6*255 ){ |
|
507
|
zFg = "black"; |
|
508
|
}else{ |
|
509
|
zFg = "white"; |
|
510
|
} |
|
511
|
if( zReq[0]!='#' ){ |
|
512
|
char zReqRGB[12]; |
|
513
|
sqlite3_snprintf(sizeof(zReqRGB),zReqRGB,"#%06x",color_name_to_rgb(zReq)); |
|
514
|
@ <tr><td style='color:%h(zFg);background-color:%h(zReq);'>\ |
|
515
|
@ Requested color "%h(zReq)" (%h(zReqRGB))</td> |
|
516
|
}else{ |
|
517
|
@ <tr><td style='color:%h(zFg);background-color:%s(zReq);'>\ |
|
518
|
@ Requested color "%h(zReq)"</td> |
|
519
|
} |
|
520
|
zBg1 = reasonable_bg_color(zReq,1); |
|
521
|
@ <td style='color:black;background-color:%h(zBg1);'>\ |
|
522
|
@ Background color for dark text: %h(zBg1)</td> |
|
523
|
zBg1 = reasonable_bg_color(zReq,2); |
|
524
|
@ <td style='color:white;background-color:%h(zBg1);'>\ |
|
525
|
@ Background color for light text: %h(zBg1)</td></tr> |
|
526
|
} |
|
527
|
if( cnt ){ |
|
528
|
@ </table> |
|
529
|
@ <hr> |
|
530
|
} |
|
531
|
@ <form method="POST"> |
|
532
|
@ <p>Enter CSS color names below and see them shifted into corresponding |
|
533
|
@ background colors above.</p> |
|
534
|
for(i=0; i<N; i++){ |
|
535
|
sqlite3_snprintf(sizeof(zNm),zNm,"b%c",'a'+i); |
|
536
|
@ <input type="text" size="30" name='%s(zNm)' \ |
|
537
|
@ value='%h(PD(zNm,azDflt[i]))'><br> |
|
538
|
} |
|
539
|
@ <input type="submit" value="Submit"> |
|
540
|
@ </form> |
|
541
|
style_finish_page(); |
|
542
|
} |
|
543
|
|