shithub: picker

Download patch

ref: 8c213f349db0bbec6fb4c503d41fcca4838ac13f
parent: db3441295e5660984a4a4f13f419d5f119c06d7b
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sat Mar 14 12:46:12 EDT 2020

implement color pallete

--- a/picker.c
+++ b/picker.c
@@ -16,56 +16,68 @@
 	Cmouse,
 	Cresize,
 	Numchan,
+
+	Offset = 6,
+	Sliderheight = 32,
 };
 
+typedef struct Color Color;
 typedef struct Mode Mode;
 
+struct Color {
+	Rectangle r;
+	double v[4];
+	double rgba[4];
+	ulong u;
+	Image *i;
+};
+
 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);
+	void (*torgb)(double *v, double *rgb);
+	void (*fromrgb)(double *rgb, double *v);
 	double max[3];
 };
 
 static void
-_hsluv2rgb(double *x, double *r, double *g, double *b)
+_hsluv2rgb(double *v, double *rgb)
 {
-	hsluv2rgb(x[0], x[1], x[2], r, g, b);
+	hsluv2rgb(v[0], v[1], v[2], rgb+0, rgb+1, rgb+2);
 }
 
 static void
-_rgb2hsluv(double r, double g, double b, double *x)
+_rgb2hsluv(double *rgb, double *v)
 {
-	rgb2hsluv(r, g, b, x+0, x+1, x+2);
+	rgb2hsluv(rgb[0], rgb[1], rgb[2], v+0, v+1, v+2);
 }
 
 static void
-_hpluv2rgb(double *x, double *r, double *g, double *b)
+_hpluv2rgb(double *v, double *rgb)
 {
-	hpluv2rgb(x[0], x[1], x[2], r, g, b);
+	hpluv2rgb(v[0], v[1], v[2], rgb+0, rgb+1, rgb+2);
 }
 
 static void
-_rgb2hpluv(double r, double g, double b, double *x)
+_rgb2hpluv(double *rgb, double *v)
 {
-	rgb2hpluv(r, g, b, x+0, x+1, x+2);
+	rgb2hpluv(rgb[0], rgb[1], rgb[2], v+0, v+1, v+2);
 }
 
 static void
-_rgbto(double *x, double *r, double *g, double *b)
+_torgb(double *v, double *rgb)
 {
-	*r = x[0];
-	*g = x[1];
-	*b = x[2];
+	v[0] = rgb[0];
+	v[1] = rgb[1];
+	v[2] = rgb[2];
 }
 
 static void
-_rgbfrom(double r, double g, double b, double *x)
+_fromrgb(double *rgb, double *v)
 {
-	x[0] = r;
-	x[1] = g;
-	x[2] = b;
+	rgb[0] = v[0];
+	rgb[1] = v[1];
+	rgb[2] = v[2];
 }
 
 static Mode modes[] = {
@@ -86,30 +98,30 @@
 	{
 		.name = "RGB",
 		.opt = 'r',
-		.torgb = _rgbto,
-		.fromrgb = _rgbfrom,
+		.torgb = _torgb,
+		.fromrgb = _fromrgb,
 		.max = {1.0, 1.0, 1.0},
 	},
 };
 
-static double *colors;
-static int ncolors, curcolor, alpha;
+static Color *colors;
+static int ncolors, curcolor, nchan;
+static Rectangle srects[3];
 static Mode *mode;
 
 static Image *
 slider(int si, int w)
 {
-	static Image *s, *sliders[3];
-	static u8int *b, *buf[3];
+	static Image *s, *sliders[4];
+	static u8int *b, *buf[4];
+	double c[4], rgb[3], dt;
 	Rectangle rect;
-	double c[3];
-	double rgb[3], dt;
-	int i, mi;
+	int i, n, mi;
 
 	rect = Rect(0, 0, w, 1);
 	s = sliders[si];
 	if (s == nil || Dx(s->r) != w) {
-		buf[si] = realloc(buf[si], 3*w);
+		buf[si] = realloc(buf[si], 4*w);
 		if (s != nil)
 			freeimage(s);
 		if ((s = sliders[si] = allocimage(display, rect, BGR24, 1, DNofill)) == nil)
@@ -117,19 +129,26 @@
 	}
 	b = buf[si];
 
-	memmove(c, &colors[4*curcolor], sizeof(c));
+	memmove(c, colors[curcolor].v, 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];
+	for (i = n = 0; i < w; i++, n += 3) {
+		mode->torgb(c, rgb);
+		b[n+0] = MAX(0, MIN(0xff, rgb[0]*0xff));
+		b[n+1] = MAX(0, MIN(0xff, rgb[1]*0xff));
+		b[n+2] = MAX(0, MIN(0xff, rgb[2]*0xff));
+		if (mi-2 == i)
+			memset(b+n, 0, 3);
+		else if (mi-1 == i)
+			memset(b+n, 0xff, 3);
+		else if (mi+1 == i)
+			memset(b+n, 0xff, 3);
+		else if (mi+2 == i)
+			memset(b+n, 0, 3);
+		else if (mi == i) {
+			memmove(colors[curcolor].rgba, rgb, sizeof(rgb));
+			colors[curcolor].u = b[n+0]<<24 | b[n+1]<<16 | b[n+2]<<8 | (colors[curcolor].u & 0xff);
 		}
 		c[si] = MIN(mode->max[si], c[si] + dt);
 	}
@@ -141,41 +160,66 @@
 static void
 redraw(void)
 {
-	Rectangle r;
-	int dh, i;
+	Rectangle r, cr;
 	Image *im;
-	double rgb[3];
-	ulong u;
 	char hex[8];
+	int i, colw;
 
 	lockdisplay(display);
 
-	//draw(screen, screen->r, display->black, nil, ZP);
+	draw(screen, screen->r, display->white, 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));
+	r.min.x += Offset;
+	r.min.y += Offset;
+	r.max.x -= Offset;
+	r.max.y = r.min.y + Sliderheight;
+
+	/* sliders */
+	for (i = 0; i < nchan; i++) {
+		srects[i] = r;
+		im = slider(i, Dx(r));
 		draw(screen, r, im, nil, ZP);
-		r.min.y += dh;
-		r.max.y += dh;
+		r.min.y += Sliderheight + Offset;
+		r.max.y += Sliderheight + Offset;
 	}
 
-	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);
+	/* palette */
+	colw = MIN(Sliderheight, (Dx(r)-(ncolors-1)*Offset)/ncolors);
+	cr = r;
+	cr.min.x += (Dx(cr) - colw*ncolors - (ncolors-1)*Offset) / 2;
+	for (i = 0; i < ncolors; i++) {
+		if (i == curcolor) {
+			freeimage(colors[i].i);
+			colors[i].i = nil;
+		}
+		if (colors[i].i == nil) {
+			colors[i].i = allocimage(display, Rect(0, 0, 1, 1), BGR24, 1, colors[i].u);
+			if (colors[i].i == nil)
+				sysfatal("allocimage: %r");
+		}
 
-	im = allocimage(display, Rect(0, 0, 1, 1), BGR24, 1, ~u);
-	sprint(hex, "#%06lux", u>>8);
+		cr.max.x = cr.min.x + colw;
+		draw(screen, cr, colors[i].i, nil, ZP);
+		colors[i].r = insetrect(cr, -3);
+		if (i == curcolor)
+			border(screen, colors[i].r, 2, display->black, ZP);
+		cr.min.x += colw + Offset;
+	}
+	r.min.y += Sliderheight + Offset;
+
+	/* current color */
+	r.max.y = screen->r.max.y - Offset;
+	draw(screen, r, colors[curcolor].i, nil, ZP);
+
+	/* current color in hex */
+	if (nchan > 3)
+		sprint(hex, "#%08lux", colors[curcolor].u);
+	else
+		sprint(hex, "#%06lux", colors[curcolor].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);
+	r.min.y += Dy(r)/2 - font->height/2;
+	stringbg(screen, r.min, display->white, ZP, font, hex, display->black, ZP);
 
 	flushimage(display, 1);
 	unlockdisplay(display);
@@ -209,12 +253,13 @@
 	};
 	char *s;
 	vlong v;
-	int i;
+	int i, j;
 
 	mode = &modes[0];
+	nchan = 3;
 	ARGBEGIN{
 	case 'a':
-		alpha = 1;
+		nchan = 4;
 		break;
 	default:
 		mode = nil;
@@ -236,21 +281,18 @@
 		fprint(2, "no colors specified\n");
 		usage();
 	}
-	colors = calloc(ncolors, 4*sizeof(double));
+	colors = calloc(ncolors, sizeof(Color));
 	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);
+		colors[i].u = v;
+		for (j = 0; j < 4; j++) {
+			colors[i].rgba[j] = (double)((v>>24)&0xff) / 255.0;
+			v <<= 8;
+		}
+		mode->fromrgb(colors[i].rgba, colors[i].v);
 	}
 
 	if (initdraw(nil, nil, "picker") < 0)
@@ -268,7 +310,7 @@
 	redraw();
 
 	for (;;) {
-
+next:
 		switch (alt(a)) {
 		case -1:
 			goto end;
@@ -290,18 +332,22 @@
 
 		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));
+				for (i = 0; i < nchan; i++) {
+					Rectangle r = srects[i];
+					r.max.x += 1;
+					if (ptinrect(m.xy, r)) {
+						colors[curcolor].v[i] = MIN(mode->max[i], (m.xy.x - r.min.x) * mode->max[i]/Dx(r));
 						redraw();
-						break;
+						goto next;
 					}
-					p.y += dh;
+				}
+				for (i = 0; i < ncolors; i++) {
+					if (ptinrect(m.xy, colors[i].r)) {
+						curcolor = i;
+						redraw();
+						goto next;
+					}
 				}
 			}
 			break;