#include <u.h>#include <libc.h>#include <thread.h>#include <draw.h>#include <memdraw.h>#include <mouse.h>#include <keyboard.h>#include <bio.h>#include <plumb.h>#include "hsluv.h" #define MAX(a,b) ((a)>=(b)?(a):(b))#define MIN(a,b) ((a)<=(b)?(a):(b))#define D2C(x) (int)MAX(0, MIN(0xff, x*256.0)) enum{ Ckey, Cmouse, Cresize, Cloaded, Numchan, Offset = 6, Sliderheight = 48,}; typedef struct Color Color;typedef struct Space Space; struct Color { char *id; Image *i; double v[4]; double rgba[4]; double rgba0[4]; /* that's for reverting back to the original */ Rectangle r; u32int u; int nchan; Color *next, *prev;}; struct Space { char *name; char opt; char single; void (*torgb)(double *v, double *rgb); void (*fromrgb)(double *rgb, double *v); double max[4];}; static void_hsluv2rgb(double *v, double *rgb){ hsluv2rgb(v[0], v[1], v[2], rgb+0, rgb+1, rgb+2);} static void_rgb2hsluv(double *rgb, double *v){ rgb2hsluv(rgb[0], rgb[1], rgb[2], v+0, v+1, v+2);} static void_hpluv2rgb(double *v, double *rgb){ hpluv2rgb(v[0], v[1], v[2], rgb+0, rgb+1, rgb+2);} static void_rgb2hpluv(double *rgb, double *v){ rgb2hpluv(rgb[0], rgb[1], rgb[2], v+0, v+1, v+2);} static void_torgb(double *v, double *rgb){ rgb[0] = v[0]; rgb[1] = v[1]; rgb[2] = v[2];} static void_fromrgb(double *rgb, double *v){ v[0] = rgb[0]; v[1] = rgb[1]; v[2] = rgb[2];} static Space spaces[] = { { .name = "HSLuv", .opt = 's', .single = 0, .torgb = _hsluv2rgb, .fromrgb = _rgb2hsluv, .max = {360.0, 100.0, 100.0, 1.0}, }, { .name = "HPLuv", .opt = 'l', .single = 0, .torgb = _hpluv2rgb, .fromrgb = _rgb2hpluv, .max = {360.0, 100.0, 100.0, 1.0}, }, { .name = "RGB", .opt = 'r', .single = 1, .torgb = _torgb, .fromrgb = _fromrgb, .max = {1.0, 1.0, 1.0, 1.0}, },}; static char *menu2i[nelem(spaces)+6];static Menu menu2 = { .item = menu2i }; static Color *colors, *color, *last;static Channel *loaded;static int ncolors;static Rectangle srects[3];static Space *space;static Image *bg, *coli;static char hex[12];static int once; static ulongrgba2u(double *rgba){ return D2C(rgba[0])<<24 | D2C(rgba[1])<<16 | D2C(rgba[2])<<8 | D2C(rgba[3]);} #pragma varargck type "©" Color*static intcolorfmt(Fmt *f){ char s[16]; Color *c; c = va_arg(f->args, Color*); if(c->nchan < 4) sprint(s, "%06ux", c->u>>8); else sprint(s, "%08ux", c->u); return fmtstrcpy(f, s);} static Image *slider(int si, int w){ static Image *s, *sliders[4]; static u8int *b, *buf[4]; double c[4], rgba[4], dt; Rectangle rect; int i, n, mi; ulong u; rect = Rect(0, 0, w, 1); s = sliders[si]; if(s == nil || Dx(s->r) != w){ buf[si] = realloc(buf[si], 4*w); if(s != nil) freeimage(s); if((s = sliders[si] = allocimage(display, rect, RGBA32, 1, DNofill)) == nil) sysfatal("allocimage: %r"); } b = buf[si]; memmove(c, color->v, sizeof(c)); if(space->single){ memset(c, 0, 3*sizeof(double)); c[si] = color->v[si]; } dt = space->max[si] / w; mi = c[si] / dt; c[si] = 0.0; for(i = n = 0; i < w; i++, n += 4){ space->torgb(c, rgba); rgba[3] = c[3]; u = rgba2u(rgba); u = setalpha(u, u&0xff); b[n] = 0xff; if(mi-2 == i) memset(b+n+1, 0, 3); else if(mi-1 == i) memset(b+n+1, 0xff, 3); else if(mi+1 == i) memset(b+n+1, 0xff, 3); else if(mi+2 == i) memset(b+n+1, 0, 3); else{ b[n+0] = u & 0xff; b[n+1] = (u>>8) & 0xff; b[n+2] = (u>>16) & 0xff; b[n+3] = (u>>24) & 0xff; } c[si] = MIN(space->max[si], c[si] + dt); } loadimage(s, rect, b, 4*w); return s;} static voidredraw(void){ Rectangle r, cr; Color *c; Image *im; int i, colw; lockdisplay(display); draw(screen, screen->r, display->white, nil, ZP); r = screen->r; r.min.x += Offset; r.min.y += Offset; r.max.x -= Offset; r.max.y = r.min.y + Sliderheight; /* sliders */ for(i = 0; i < color->nchan; i++){ srects[i] = r; im = slider(i, Dx(r)); draw(screen, r, bg, nil, ZP); draw(screen, r, im, nil, ZP); r.min.y += Sliderheight + Offset; r.max.y += Sliderheight + Offset; } /* current color is changed on redraw, always */ freeimage(color->i); color->i = nil; /* palette */ colw = MIN(Sliderheight, (Dx(r)-(ncolors-1)*Offset)/ncolors); cr = r; cr.min.x += (Dx(cr) - colw*ncolors - (ncolors-1)*Offset) / 2; for(c = colors; c != nil; c = c->next){ if(c->i == nil){ if((c->i = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, setalpha(c->u|0xff, c->u&0xff))) == nil) sysfatal("allocimage: %r"); } cr.max.x = cr.min.x + colw; draw(screen, cr, bg, nil, ZP); draw(screen, cr, c->i, nil, ZP); border(screen, cr, 1, display->black, ZP); c->r = insetrect(cr, -3); if(c == color) border(screen, c->r, 3, display->black, ZP); cr.min.x += colw + Offset; } r.min.y += Sliderheight + Offset; /* current color */ r.max.y = screen->r.max.y - Offset; draw(coli, bg->r, bg, nil, ZP); draw(coli, bg->r, color->i, nil, ZP); draw(screen, r, coli, nil, ZP); /* current color id */ r.min.x += Dx(r)/2 - stringwidth(font, color->id)/2; stringbg(screen, r.min, display->white, ZP, font, color->id, display->black, ZP); /* current color in hex */ r.min.y += font->height; sprint(hex, "%©", color); r.min.x = screen->r.min.x + Dx(screen->r)/2 - stringwidth(font, hex)/2; stringbg(screen, r.min, display->white, ZP, font, hex, display->black, ZP); flushimage(display, 1); unlockdisplay(display);} static voidusage(void){ int i; print("usage: %s [-e] [-", argv0); for(i = 0; i < nelem(spaces); i++) print("%c", spaces[i].opt); print("]\n"); threadexitsall("usage");} static voidloadbg(void){ Rectangle r; u8int *d; int i, j; r = Rect(0, 0, Sliderheight, Sliderheight); d = calloc(1, Sliderheight*Sliderheight); for(i = 0; i < Sliderheight/2; i++){ for(j = 0; j < Sliderheight/2; j++) d[j*Sliderheight+i] = 0xff; } for(; i < Sliderheight; i++){ for(j = Sliderheight/2; j < Sliderheight; j++) d[j*Sliderheight+i] = 0xff; } if((bg = allocimage(display, r, GREY8, 1, DNofill)) == nil) sysfatal("allocimage: %r"); if(loadimage(bg, r, d, Sliderheight*Sliderheight) < 0) sysfatal("loadimage: %r"); free(d);} static intprintcolor(int f, Color *c){ char s[64]; int n; n = snprint(s, sizeof(s), "%s\t%©\n", c->id, c); return write(f, s, n) == n ? 0 : -1;} static inthex2color(char *h, Color *c){ vlong v; int i, n; char *e; n = strlen(h); if(n != 6 && n != 8){ werrstr("components: %d", n); return -1; } c->nchan = n == 6 ? 3 : 4; v = strtoll(h, &e, 16); if(v == 0 && (e == h || *e || v < 0 || (n == 6 && v > 0xffffff) || (n == 8 && v > 0xffffffff))){ werrstr("color: '%s'", h); return -1; } if(c->nchan < 4){ v <<= 8; v |= 0xff; } c->u = v; for(i = 0; i < 4; i++){ c->rgba[i] = (double)((v>>24)&0xff) / 255.0; v <<= 8; } c->v[3] = c->rgba[3]; space->fromrgb(c->rgba, c->v); return 0;} static intline2color(char *s, Color *c){ char *a[3]; int n; if((n = tokenize(s, a, nelem(a))) < 2){ werrstr("columns: %d", n); return -1; } if(hex2color(a[1], c) != 0) return -1; c->id = strdup(a[0]); return 0;} static voidreadcolors(void *x){ Color *c, *new; Biobuf *b; char *s; char tmp[64]; int i, n; b = x; n = sprint(tmp, "readcolors "); fd2path(Bfildes(b), tmp+n, sizeof(tmp)-n); threadsetname(tmp); new = nil; for(i = 1; (s = Brdstr(b, '\n', 1)) != nil; i++){ if(new == nil) new = calloc(1, sizeof(Color)); n = line2color(s, new); free(s); if(n != 0){ fprint(2, "readcolors: line %d: %r\n", i); continue; } lockdisplay(display); for(c = colors; c != nil; c = c->next){ if(strcmp(c->id, new->id) == 0){ free(c->id); new->prev = c->prev; new->next = c->next; memmove(new->rgba0, c->rgba0, sizeof(new->rgba0)); memmove(c, new, sizeof(*c)); break; } } if(c == nil){ c = new; memmove(c->rgba0, c->rgba, sizeof(c->rgba)); if(last != nil) last->next = new; new->prev = last; last = new; if(colors == nil) colors = color = new; new = nil; ncolors++; } if(!once) printcolor(1, c); unlockdisplay(display); sendul(loaded, 0); } Bterm(b); threadexits(nil);} static voiddump(int f){ Color *c; for(c = colors; c != nil; c = c->next) printcolor(f, c);} static voidloadtheme(char *filename){ Biobuf *b; if((b = Bopen(filename, OREAD)) != nil) proccreate(readcolors, b, 4096);} static voidplumbproc(void *){ int f; Plumbmsg *m; threadsetname("plumb"); if((f = plumbopen("picker", OREAD)) >= 0){ while((m = plumbrecv(f)) != nil){ loadtheme(m->data); plumbfree(m); } } threadexits(nil);} voidthreadmain(int argc, char **argv){ Mousectl *mctl; Keyboardctl *kctl; Biobuf *b; Color *c; Rune r; Mouse m; Alt a[Numchan+1] = { [Ckey] = { nil, &r, CHANRCV }, [Cmouse] = { nil, &m, CHANRCV }, [Cresize] = { nil, nil, CHANRCV }, [Cloaded] = { nil, nil, CHANRCV }, { nil, nil, CHANEND }, }; int i, oldbuttons, slider, menusnarf, menusnarfall, menurevert, menurevertall, menuexit; ulong u; char buf[16]; fmtinstall(L'©', colorfmt); space = &spaces[0];Lines 1–500 of 690. Load more
#include <u.h> #include <libc.h> #include <thread.h> #include <draw.h> #include <memdraw.h> #include <mouse.h> #include <keyboard.h> #include <bio.h> #include <plumb.h> #include "hsluv.h" #define MAX(a,b) ((a)>=(b)?(a):(b)) #define MIN(a,b) ((a)<=(b)?(a):(b)) #define D2C(x) (int)MAX(0, MIN(0xff, x*256.0)) enum { Ckey, Cmouse, Cresize, Cloaded, Numchan, Offset = 6, Sliderheight = 48, }; typedef struct Color Color; typedef struct Space Space; struct Color { char *id; Image *i; double v[4]; double rgba[4]; double rgba0[4]; /* that's for reverting back to the original */ Rectangle r; u32int u; int nchan; Color *next, *prev; }; struct Space { char *name; char opt; char single; void (*torgb)(double *v, double *rgb); void (*fromrgb)(double *rgb, double *v); double max[4]; }; static void _hsluv2rgb(double *v, double *rgb) { hsluv2rgb(v[0], v[1], v[2], rgb+0, rgb+1, rgb+2); } static void _rgb2hsluv(double *rgb, double *v) { rgb2hsluv(rgb[0], rgb[1], rgb[2], v+0, v+1, v+2); } static void _hpluv2rgb(double *v, double *rgb) { hpluv2rgb(v[0], v[1], v[2], rgb+0, rgb+1, rgb+2); } static void _rgb2hpluv(double *rgb, double *v) { rgb2hpluv(rgb[0], rgb[1], rgb[2], v+0, v+1, v+2); } static void _torgb(double *v, double *rgb) { rgb[0] = v[0]; rgb[1] = v[1]; rgb[2] = v[2]; } static void _fromrgb(double *rgb, double *v) { v[0] = rgb[0]; v[1] = rgb[1]; v[2] = rgb[2]; } static Space spaces[] = { { .name = "HSLuv", .opt = 's', .single = 0, .torgb = _hsluv2rgb, .fromrgb = _rgb2hsluv, .max = {360.0, 100.0, 100.0, 1.0}, }, { .name = "HPLuv", .opt = 'l', .single = 0, .torgb = _hpluv2rgb, .fromrgb = _rgb2hpluv, .max = {360.0, 100.0, 100.0, 1.0}, }, { .name = "RGB", .opt = 'r', .single = 1, .torgb = _torgb, .fromrgb = _fromrgb, .max = {1.0, 1.0, 1.0, 1.0}, }, }; static char *menu2i[nelem(spaces)+6]; static Menu menu2 = { .item = menu2i }; static Color *colors, *color, *last; static Channel *loaded; static int ncolors; static Rectangle srects[3]; static Space *space; static Image *bg, *coli; static char hex[12]; static int once; static ulong rgba2u(double *rgba) { return D2C(rgba[0])<<24 | D2C(rgba[1])<<16 | D2C(rgba[2])<<8 | D2C(rgba[3]); } #pragma varargck type "©" Color* static int colorfmt(Fmt *f) { char s[16]; Color *c; c = va_arg(f->args, Color*); if(c->nchan < 4) sprint(s, "%06ux", c->u>>8); else sprint(s, "%08ux", c->u); return fmtstrcpy(f, s); } static Image * slider(int si, int w) { static Image *s, *sliders[4]; static u8int *b, *buf[4]; double c[4], rgba[4], dt; Rectangle rect; int i, n, mi; ulong u; rect = Rect(0, 0, w, 1); s = sliders[si]; if(s == nil || Dx(s->r) != w){ buf[si] = realloc(buf[si], 4*w); if(s != nil) freeimage(s); if((s = sliders[si] = allocimage(display, rect, RGBA32, 1, DNofill)) == nil) sysfatal("allocimage: %r"); } b = buf[si]; memmove(c, color->v, sizeof(c)); if(space->single){ memset(c, 0, 3*sizeof(double)); c[si] = color->v[si]; } dt = space->max[si] / w; mi = c[si] / dt; c[si] = 0.0; for(i = n = 0; i < w; i++, n += 4){ space->torgb(c, rgba); rgba[3] = c[3]; u = rgba2u(rgba); u = setalpha(u, u&0xff); b[n] = 0xff; if(mi-2 == i) memset(b+n+1, 0, 3); else if(mi-1 == i) memset(b+n+1, 0xff, 3); else if(mi+1 == i) memset(b+n+1, 0xff, 3); else if(mi+2 == i) memset(b+n+1, 0, 3); else{ b[n+0] = u & 0xff; b[n+1] = (u>>8) & 0xff; b[n+2] = (u>>16) & 0xff; b[n+3] = (u>>24) & 0xff; } c[si] = MIN(space->max[si], c[si] + dt); } loadimage(s, rect, b, 4*w); return s; } static void redraw(void) { Rectangle r, cr; Color *c; Image *im; int i, colw; lockdisplay(display); draw(screen, screen->r, display->white, nil, ZP); r = screen->r; r.min.x += Offset; r.min.y += Offset; r.max.x -= Offset; r.max.y = r.min.y + Sliderheight; /* sliders */ for(i = 0; i < color->nchan; i++){ srects[i] = r; im = slider(i, Dx(r)); draw(screen, r, bg, nil, ZP); draw(screen, r, im, nil, ZP); r.min.y += Sliderheight + Offset; r.max.y += Sliderheight + Offset; } /* current color is changed on redraw, always */ freeimage(color->i); color->i = nil; /* palette */ colw = MIN(Sliderheight, (Dx(r)-(ncolors-1)*Offset)/ncolors); cr = r; cr.min.x += (Dx(cr) - colw*ncolors - (ncolors-1)*Offset) / 2; for(c = colors; c != nil; c = c->next){ if(c->i == nil){ if((c->i = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, setalpha(c->u|0xff, c->u&0xff))) == nil) sysfatal("allocimage: %r"); } cr.max.x = cr.min.x + colw; draw(screen, cr, bg, nil, ZP); draw(screen, cr, c->i, nil, ZP); border(screen, cr, 1, display->black, ZP); c->r = insetrect(cr, -3); if(c == color) border(screen, c->r, 3, display->black, ZP); cr.min.x += colw + Offset; } r.min.y += Sliderheight + Offset; /* current color */ r.max.y = screen->r.max.y - Offset; draw(coli, bg->r, bg, nil, ZP); draw(coli, bg->r, color->i, nil, ZP); draw(screen, r, coli, nil, ZP); /* current color id */ r.min.x += Dx(r)/2 - stringwidth(font, color->id)/2; stringbg(screen, r.min, display->white, ZP, font, color->id, display->black, ZP); /* current color in hex */ r.min.y += font->height; sprint(hex, "%©", color); r.min.x = screen->r.min.x + Dx(screen->r)/2 - stringwidth(font, hex)/2; stringbg(screen, r.min, display->white, ZP, font, hex, display->black, ZP); flushimage(display, 1); unlockdisplay(display); } static void usage(void) { int i; print("usage: %s [-e] [-", argv0); for(i = 0; i < nelem(spaces); i++) print("%c", spaces[i].opt); print("]\n"); threadexitsall("usage"); } static void loadbg(void) { Rectangle r; u8int *d; int i, j; r = Rect(0, 0, Sliderheight, Sliderheight); d = calloc(1, Sliderheight*Sliderheight); for(i = 0; i < Sliderheight/2; i++){ for(j = 0; j < Sliderheight/2; j++) d[j*Sliderheight+i] = 0xff; } for(; i < Sliderheight; i++){ for(j = Sliderheight/2; j < Sliderheight; j++) d[j*Sliderheight+i] = 0xff; } if((bg = allocimage(display, r, GREY8, 1, DNofill)) == nil) sysfatal("allocimage: %r"); if(loadimage(bg, r, d, Sliderheight*Sliderheight) < 0) sysfatal("loadimage: %r"); free(d); } static int printcolor(int f, Color *c) { char s[64]; int n; n = snprint(s, sizeof(s), "%s\t%©\n", c->id, c); return write(f, s, n) == n ? 0 : -1; } static int hex2color(char *h, Color *c) { vlong v; int i, n; char *e; n = strlen(h); if(n != 6 && n != 8){ werrstr("components: %d", n); return -1; } c->nchan = n == 6 ? 3 : 4; v = strtoll(h, &e, 16); if(v == 0 && (e == h || *e || v < 0 || (n == 6 && v > 0xffffff) || (n == 8 && v > 0xffffffff))){ werrstr("color: '%s'", h); return -1; } if(c->nchan < 4){ v <<= 8; v |= 0xff; } c->u = v; for(i = 0; i < 4; i++){ c->rgba[i] = (double)((v>>24)&0xff) / 255.0; v <<= 8; } c->v[3] = c->rgba[3]; space->fromrgb(c->rgba, c->v); return 0; } static int line2color(char *s, Color *c) { char *a[3]; int n; if((n = tokenize(s, a, nelem(a))) < 2){ werrstr("columns: %d", n); return -1; } if(hex2color(a[1], c) != 0) return -1; c->id = strdup(a[0]); return 0; } static void readcolors(void *x) { Color *c, *new; Biobuf *b; char *s; char tmp[64]; int i, n; b = x; n = sprint(tmp, "readcolors "); fd2path(Bfildes(b), tmp+n, sizeof(tmp)-n); threadsetname(tmp); new = nil; for(i = 1; (s = Brdstr(b, '\n', 1)) != nil; i++){ if(new == nil) new = calloc(1, sizeof(Color)); n = line2color(s, new); free(s); if(n != 0){ fprint(2, "readcolors: line %d: %r\n", i); continue; } lockdisplay(display); for(c = colors; c != nil; c = c->next){ if(strcmp(c->id, new->id) == 0){ free(c->id); new->prev = c->prev; new->next = c->next; memmove(new->rgba0, c->rgba0, sizeof(new->rgba0)); memmove(c, new, sizeof(*c)); break; } } if(c == nil){ c = new; memmove(c->rgba0, c->rgba, sizeof(c->rgba)); if(last != nil) last->next = new; new->prev = last; last = new; if(colors == nil) colors = color = new; new = nil; ncolors++; } if(!once) printcolor(1, c); unlockdisplay(display); sendul(loaded, 0); } Bterm(b); threadexits(nil); } static void dump(int f) { Color *c; for(c = colors; c != nil; c = c->next) printcolor(f, c); } static void loadtheme(char *filename) { Biobuf *b; if((b = Bopen(filename, OREAD)) != nil) proccreate(readcolors, b, 4096); } static void plumbproc(void *) { int f; Plumbmsg *m; threadsetname("plumb"); if((f = plumbopen("picker", OREAD)) >= 0){ while((m = plumbrecv(f)) != nil){ loadtheme(m->data); plumbfree(m); } } threadexits(nil); } void threadmain(int argc, char **argv) { Mousectl *mctl; Keyboardctl *kctl; Biobuf *b; Color *c; Rune r; Mouse m; Alt a[Numchan+1] = { [Ckey] = { nil, &r, CHANRCV }, [Cmouse] = { nil, &m, CHANRCV }, [Cresize] = { nil, nil, CHANRCV }, [Cloaded] = { nil, nil, CHANRCV }, { nil, nil, CHANEND }, }; int i, oldbuttons, slider, menusnarf, menusnarfall, menurevert, menurevertall, menuexit; ulong u; char buf[16]; fmtinstall(L'©', colorfmt); space = &spaces[0];