ref: 3897a967274ce9d36bb9ea10432bb7bec5de8b16
dir: /picker.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <draw.h> #include <memdraw.h> #include <mouse.h> #include <keyboard.h> #include "hsluv.h" #define MAX(a,b) ((a)>=(b)?(a):(b)) #define MIN(a,b) ((a)<=(b)?(a):(b)) enum { Ckey, Cmouse, Cresize, Numchan, }; typedef struct Mode Mode; struct Mode { char *name; char opt; void (*torgb)(double *x, double *r, double *g, double *b); void (*fromrgb)(double r, double g, double b, double *x); double max[3]; }; static void _hsluv2rgb(double *x, double *r, double *g, double *b) { hsluv2rgb(x[0], x[1], x[2], r, g, b); } static void _rgb2hsluv(double r, double g, double b, double *x) { rgb2hsluv(r, g, b, x+0, x+1, x+2); } static void _hpluv2rgb(double *x, double *r, double *g, double *b) { hpluv2rgb(x[0], x[1], x[2], r, g, b); } static void _rgb2hpluv(double r, double g, double b, double *x) { rgb2hpluv(r, g, b, x+0, x+1, x+2); } static void _rgbto(double *x, double *r, double *g, double *b) { *r = x[0]; *g = x[1]; *b = x[2]; } static void _rgbfrom(double r, double g, double b, double *x) { x[0] = r; x[1] = g; x[2] = b; } static Mode modes[] = { { .name = "HSLuv", .opt = 's', .torgb = _hsluv2rgb, .fromrgb = _rgb2hsluv, .max = {360.0, 100.0, 100.0}, }, { .name = "HPLuv", .opt = 'l', .torgb = _hpluv2rgb, .fromrgb = _rgb2hpluv, .max = {360.0, 100.0, 100.0}, }, { .name = "RGB", .opt = 'r', .torgb = _rgbto, .fromrgb = _rgbfrom, .max = {1.0, 1.0, 1.0}, }, }; static double *colors; static int ncolors, alpha; static Mode *mode; static Image * gradient(double *color, int w, int e) { Rectangle rect; u8int *data; Image *im; double c[3]; double r, g, b, x; int i, mi; rect = Rect(0, 0, w, 1); if ((im = allocimage(display, rect, BGR24, 1, DNofill)) == nil) sysfatal("allocimage: %r"); memmove(c, color, sizeof(c)); data = malloc(3*w); x = mode->max[e] / w; mi = c[e] / x; c[e] = 0.0; for (i = 0; i < w; i++) { mode->torgb(c, &r, &g, &b); data[i*3+0] = r*255.0; data[i*3+1] = g*255.0; data[i*3+2] = b*255.0; if (mi == i) { data[i*3+0] = ~data[i*3+0]; data[i*3+1] = ~data[i*3+1]; data[i*3+2] = ~data[i*3+2]; } c[e] += x; if (c[e] > mode->max[e]) c[e] = mode->max[e]; } loadimage(im, rect, data, 3*w); free(data); return im; } static void redraw(void) { Rectangle re; int dh, i; Image *im; double r, g, b; ulong u; char hex[8]; lockdisplay(display); //draw(screen, screen->r, display->white, nil, ZP); re = screen->r; dh = Dy(re) / 4; re.max.y = re.min.y + dh; for (i = 0; i < 3; i++) { im = gradient(&colors[4*0], Dx(screen->r), i); draw(screen, re, im, nil, ZP); freeimage(im); re.min.y += dh; re.max.y += dh; } mode->torgb(&colors[4*0], &r, &g, &b); u = (int)(r*255.0)<<24 | (int)(r*255.0)<<24 | (int)(g*255.0)<<16 | (int)(b*255.0)<<8 | 0xff; im = allocimage(display, Rect(0, 0, 1, 1), BGR24, 1, u); draw(screen, re, im, nil, ZP); freeimage(im); im = allocimage(display, Rect(0, 0, 1, 1), BGR24, 1, ~u); sprint(hex, "#%06lux", u>>8); re.min.x += Dx(re)/2 - 7*stringwidth(font, "#")/2; re.max.x += dh/2 - font->height/2; string(screen, re.min, im, ZP, font, hex); freeimage(im); flushimage(display, 1); unlockdisplay(display); } static void usage(void) { int i; print("usage: %s [-a] [-", argv0); for (i = 0; i < nelem(modes); i++) print("%c", modes[i].opt); print("] 0xrrggbbaa ...\n"); threadexitsall("usage"); } void threadmain(int argc, char **argv) { Mousectl *mctl; Keyboardctl *kctl; Rune r; Mouse m; Alt a[Numchan+1] = { [Ckey] = { nil, &r, CHANRCV }, [Cmouse] = { nil, &m, CHANRCV }, [Cresize] = { nil, nil, CHANRCV }, { nil, nil, CHANEND }, }; char *s; vlong v; int i; mode = &modes[0]; ARGBEGIN{ case 'a': alpha = 1; break; default: mode = nil; for (i = 0; i < nelem(modes); i++) { if (modes[i].opt == ARGC()) { mode = &modes[i]; break; } } if (mode == nil) { fprint(2, "unknown mode '%c'\n", ARGC()); usage(); } break; }ARGEND ncolors = argc; if (ncolors < 1) { fprint(2, "no colors specified\n"); usage(); } colors = calloc(ncolors, 4*sizeof(double)); for (i = 0; i < ncolors; i++) { double r, g, b; if ((v = strtoll(argv[i], &s, 0)) == 0 && (s == argv[i] || *s || v > 0xffffffff || v < 0)) { fprint(2, "invalid color '%s'\n", argv[i]); usage(); } mode->fromrgb( (double)((v>>24)&0xff) / 255.0, (double)((v>>16)&0xff) / 255.0, (double)((v>>8)&0xff) / 255.0, &colors[i*4] ); colors[i*4+3] = (double)(v&0xff) / 255.0; mode->torgb(&colors[i*4], &r, &g, &b); } if (initdraw(nil, nil, "picker") < 0) sysfatal("initdraw: %r"); if ((kctl = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); a[Ckey].c = kctl->c; if ((mctl = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); a[Cmouse].c = mctl->c; a[Cresize].c = mctl->resizec; display->locking = 1; unlockdisplay(display); redraw(); for (;;) { switch (alt(a)) { case -1: goto end; case Ckey: switch (r) { case Kdel: goto end; } break; case Cmouse: if (m.buttons == 1) { Point p; int dh; p = screen->r.min; dh = Dy(screen->r)/4; m.xy.x = MAX(screen->r.min.x, MIN(screen->r.max.x, m.xy.x)); for (i = 0; i < 3; i++) { if (m.xy.y >= p.y && m.xy.y < p.y+dh) { colors[4*0 + i] = MIN(mode->max[i], (m.xy.x - screen->r.min.x) * mode->max[i]/Dx(screen->r)); redraw(); break; } p.y += dh; } } break; case Cresize: getwindow(display, Refnone); redraw(); break; } } end: threadexitsall(nil); }