Sigrid Solveig Haflínudóttirdraw to a backing image first82e9ef34 years agoHistory
690 lines · 12.9 KB · C
RawDownload
#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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t