ref: db3441295e5660984a4a4f13f419d5f119c06d7b
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, curcolor, alpha; static Mode *mode; static Image * slider(int si, int w) { static Image *s, *sliders[3]; static u8int *b, *buf[3]; Rectangle rect; double c[3]; double rgb[3], dt; int i, mi; rect = Rect(0, 0, w, 1); s = sliders[si]; if (s == nil || Dx(s->r) != w) { buf[si] = realloc(buf[si], 3*w); if (s != nil) freeimage(s); if ((s = sliders[si] = allocimage(display, rect, BGR24, 1, DNofill)) == nil) sysfatal("allocimage: %r"); } b = buf[si]; memmove(c, &colors[4*curcolor], sizeof(c)); dt = mode->max[si] / w; mi = c[si] / dt; c[si] = 0.0; for (i = 0; i < w; i++) { mode->torgb(c, &rgb[0], &rgb[1], &rgb[2]); b[i*3+0] = rgb[0]*255.0; b[i*3+1] = rgb[1]*255.0; b[i*3+2] = rgb[2]*255.0; if (mi == i) { b[i*3+0] = ~b[i*3+0]; b[i*3+1] = ~b[i*3+1]; b[i*3+2] = ~b[i*3+2]; } c[si] = MIN(mode->max[si], c[si] + dt); } loadimage(s, rect, b, 3*w); return s; } static void redraw(void) { Rectangle r; int dh, i; Image *im; double rgb[3]; ulong u; char hex[8]; lockdisplay(display); //draw(screen, screen->r, display->black, nil, ZP); r = screen->r; dh = Dy(r) / 4; r.max.y = r.min.y + dh; for (i = 0; i < 3; i++) { im = slider(i, Dx(screen->r)); draw(screen, r, im, nil, ZP); r.min.y += dh; r.max.y += dh; } mode->torgb(&colors[4*curcolor], &rgb[0], &rgb[1], &rgb[2]); for (i = 0; i < 3; i++) rgb[i] = MAX(0.0, MIN(255.0, rgb[i]*255.0)); u = (ulong)rgb[0]<<24 | (ulong)rgb[1]<<16 | (ulong)rgb[2]<<8 | 0xff; im = allocimage(display, Rect(0, 0, 1, 1), BGR24, 1, u); draw(screen, r, im, nil, ZP); freeimage(im); im = allocimage(display, Rect(0, 0, 1, 1), BGR24, 1, ~u); sprint(hex, "#%06lux", u>>8); r.min.x += Dx(r)/2 - 7*stringwidth(font, "#")/2; r.min.y += dh/2 - font->height/2; string(screen, r.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 Kleft: curcolor = MAX(0, curcolor-1); redraw(); break; case Kright: curcolor = MIN(ncolors-1, curcolor+1); redraw(); break; 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*curcolor+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); }