]> git.neil.brown.name Git - edlib.git/blob - lib-colourmap.c
TODO: clean out done items.
[edlib.git] / lib-colourmap.c
1 /*
2  * Copyright Neil Brown ©2019-2023 <neil@brown.name>
3  * May be distributed under terms of GPLv2 - see file:COPYING
4  *
5  * Provide a colour-name service.
6  * A client (normally a display) call "colour:map" passing a
7  * string name of a colour.  The callback is passed the chosen colour
8  * as RGB values (0-1000) in num1 num2 and x, and as string in hex format #RRggBB
9  * Alternate interfaces are "colour:map:bg" and "colour:map:fg"
10  * The are passes a reference colour in 'str2' (#rrggbb).
11  * for colour:map:bg, the reference should be the default background
12  * for colour:map:fg, the reference should be the chosen background.
13  * One day these might modify the reult to provide better contrast.
14  *
15  * Colours have a base name and modifiers.
16  * The base name is either a word (e.g. "green" "rebeccapurple") or a
17  * hex colour #rrggbb.  In either case, case is ignored.
18  * The modifier can adjust value or saturation.
19  * -nn (0-99) reduces the brightness - scales each channel towards zero.
20  *    0 means black. 99 means no-change
21  * +nn (0-99) reduces saturation - scales each channel towards max.
22  *    0 means no change, 99 means white.
23  * So "white-50" and "black+50" are both mid-grey.  "yellow-90+90" is a pale yellow.
24  */
25
26 #define _GNU_SOURCE for_asprintf
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include "core.h"
31
32 static struct colours {
33         char *name;
34         int r,g,b;
35 } colours[] = {
36         { "black",       0,    0,    0 },
37         { "white",    1000, 1000, 1000 },
38         { "red",      1000,    0,    0 },
39         { "green",       0, 1000,    0 },
40         { "blue",        0,    0, 1000 },
41         { "yellow",   1000, 1000,    0 },
42         { "magenta",  1000,    0, 1000 },
43         { "cyan",        0, 1000, 1000 },
44         { "darkblue",    0,    0,  550 },
45         { "purple",    500,    0,  500 },
46         { "grey",      500,  500,  500 },
47         { "pink",     1000,  800,  800 },
48 };
49
50 static void gethex(char *col safe, int rgb[])
51 {
52         char b[3];
53         int i;
54
55         b[2] = 0;
56         if (strlen(col) != 6)
57                 return;
58         for (i = 0; i < 3; i++) {
59                 b[0] = col[i*2];
60                 b[1] = col[i+2+1];
61                 rgb[i] = strtoul(b, NULL, 16) * 1000 / 255;
62         }
63 }
64
65 static bool find_colour(char *col, int rgb[])
66 {
67         unsigned int i;
68
69         for (i = 0; i < ARRAY_SIZE(colours); i++) {
70                 if (strcasecmp(col, colours[i].name) == 0) {
71                         rgb[0] = colours[i].r;
72                         rgb[1] = colours[i].g;
73                         rgb[2] = colours[i].b;
74                         return True;
75                 }
76         }
77         return False;
78 }
79
80 static void add_value(char *n, int rgb[])
81 {
82         int scale = atoi(n);
83         int i;
84
85         if (scale < 0 || scale > 99)
86                 return;
87         for (i = 0; i < 3; i++)
88                 rgb[i] = rgb[i] * scale / 99;
89 }
90
91 static void add_sat(char *n, int rgb[])
92 {
93         int scale = atoi(n);
94         int i;
95
96         if (scale < 0 || scale > 99)
97                 return;
98         for (i = 0; i < 3; i++)
99                 rgb[i] = 1000 - ( (99 - scale) * (1000 - rgb[i]) / 99);
100 }
101
102 DEF_CMD(colour_map)
103 {
104         char *col;
105         char *m, *p;
106         int rgb[3] = { 500, 500, 500};
107         int ret;
108
109         if (!ci->str)
110                 return Enoarg;
111         col = strdup(ci->str);
112         p = strchr(col, '+');
113         if (p)
114                 *p++ = 0;
115         m = strchr(col, '-');
116         if (m)
117                 *m++ = 0;
118         if (col[0] == '#')
119                 gethex(col+1, rgb);
120         else if (!find_colour(col, rgb))
121                 find_colour("grey", rgb);
122         if (m)
123                 add_value(m, rgb);
124         if (p)
125                 add_sat(p, rgb);
126         free(col);
127         asprintf(&col, "#%02x%02x%02x", rgb[0]*255/1000,
128                  rgb[1]*255/1000, rgb[2]*255/1000);
129         ret = comm_call(ci->comm2, "colour:callback", ci->focus,
130                         rgb[0], NULL, col,
131                         rgb[1], NULL, NULL, rgb[2], 0);
132         free(col);
133         return ret;
134 }
135
136 void edlib_init(struct pane *ed safe)
137 {
138         call_comm("global-set-command", ed, &colour_map,
139                   0, NULL, "colour:map");
140         call_comm("global-set-command-prefix", ed, &colour_map,
141                   0, NULL, "colour:map:");
142 }