shithub: pain

Download patch

ref: 1c2839d17d4dbe1e5aabd448aa565353ba8cd4af
parent: 9b6630e3b2aa191c282cf59345fe874305ee3638
author: jmq <jmq@jmq.sh>
date: Sat Aug 23 11:52:44 EDT 2025

functional color picker

--- a/pill/pill.c
+++ b/pill/pill.c
@@ -20,6 +20,8 @@
 #define COLORPICKERRADIUS .25
 #define INNERBORDERRADIUS	(COLORPICKERPADDING + COLORPICKERRADIUS)
 #define RECTANGLE(w, h) ((Rectangle){(Point){(0),(0)}, (Point){(w),(h)}})
+#define COLORINDICATORSIZE 0.15
+#define VALUEINCREASE 0.01
 
 Image * VirtualWindow = nil;
 Image * HuePicker = nil;
@@ -38,8 +40,22 @@
 float SaturationStart = .50;
 float HueStart = PI*.35;
 float Value = 1.0;
+float Hue = 0.f;
+float Saturation = 1.0;
 int RunApp = 1;
-int UpdateCircle = 1;
+int UpdateCanvas = 1;
+Point MouseGlobalPosition;
+Point MouseRelativePosition;
+double MouseAngle;
+double MouseRadius;
+double MouseHueRadiusStart;
+double MouseHueRadiusEnd;
+int MouseInHue;
+int MouseInGradient;
+u32int Color;
+u32int ColorUnderMouse;
+int ShouldDraw = 1;
+int UpdateGradient = 1;
 
 int resizeimage(Image * d, Image * s)
 {
@@ -209,6 +225,10 @@
 	Point c, e;
 	int rc, dx, dy;
 
+	if (UpdateGradient == 0) {
+		return;
+	}
+
 	dx = Dx(Gradient->r);
 	dy = Dy(Gradient->r);
 	c.x = dx/2 + 1;
@@ -231,11 +251,22 @@
 				Value);
 		}
 	}
+	for (t = PI-CIRCLESHIFT; t < (PI - CIRCLESHIFT + CIRCLESLICE); t += i) {
+		ct = cos(t);
+		st = sin(t);
+		for (s = 0; s < l; s += 0.1) {
+			e.x = c.x + s * ct;
+			e.y = c.y + s * st;
+			RawGradient[dx * e.y + e.x] = DWhite;
+		}
+	}
 
 	rc = loadimage(Gradient, Gradient->r, (uchar *)RawGradient, RawGradientSize);
 	if (rc < 0) {
 		sysfatal("loadimage: %r");
 	}
+
+	UpdateGradient = 0;
 }
 
 static void
@@ -293,10 +324,61 @@
 }
 
 static void
+updatecolorindicator(void)
+{
+	Image * c;
+	Rectangle r;
+
+	if (VirtualWindow == nil) {
+		return;
+	}
+
+	c = allocimage(display, RECTANGLE(1, 1), RGBA32, 1, Color);
+	if (c == nil) {
+		sysfatal("allocimage: %r");
+	}
+	
+	r = RECTANGLE( ((float)Dx(screen->r)) * COLORINDICATORSIZE,
+		((float)Dx(screen->r)) * COLORINDICATORSIZE);
+	r.min = screen->r.min;
+	r.max = addpt(r.max, r.min);
+	draw(screen, r, c, nil, ZP);
+	freeimage(c);
+}
+
+u32int
+pickcolor(void)
+{
+	Image * c;
+	u32int colors[4];
+
+	if (VirtualWindow == nil) {
+		return DWhite;
+	}
+
+	//print("r: %R\n", r);
+	c = allocimage(display, RECTANGLE(1,1), RGBA32, 1, DNofill);
+	if (c == nil) {
+		sysfatal("allocimage: %r");
+	}
+	
+	drawop(c, c->r, VirtualWindow, nil, MouseGlobalPosition, S);
+	unloadimage(c, c->r, (uchar*)colors, sizeof(colors));
+	freeimage(c);
+
+	return colors[0];
+}
+
+static void
 drawcanvas(void)
 {
+	if (ShouldDraw == 0) {
+		return;
+	}
 	draw(screen, screen->r, Background, nil, ZP);
 	draw(screen, screen->r, VirtualWindow, nil, screen->r.min);
+	updatecolorindicator();
+	ShouldDraw = 0;
 }
 
 void
@@ -310,33 +392,103 @@
 		sysfatal("setbackground: %r");
 }
 
+static void
+updatecanvas(void)
+{
+	int rc;
 
+	if (VirtualWindow == nil || 
+		Dx(VirtualWindow->r) != Dx(screen->r) || 
+		Dy(VirtualWindow->r) != Dx(screen->r) || UpdateCanvas) {
+
+		if (VirtualWindow != nil) {
+			freeimage(VirtualWindow);
+		}
+
+		VirtualWindow = allocimage(display, screen->r, RGBA32, 0, DTransparent);
+		if (VirtualWindow == nil) {
+			sysfatal("initcanvas: %r");
+		}
+
+	 	rc = resizeimage(VirtualWindow, HuePicker);
+	 	if (rc < 0) {
+	 		sysfatal("resizeimage: %r");
+	 	}
+
+	 	rc = resizeimage(VirtualWindow, Gradient);
+	 	if (rc < 0) {
+	 		sysfatal("resizeimage: %r");
+	 	}
+	}
+}
+
 static void
 initcanvas(void)
 {
-	int rc;
+	setbackground(BACKGROUNDCOLOR);
+	ShouldDraw = 1;
+}
 
-	if (VirtualWindow != nil) {
-		freeimage(VirtualWindow);
+void
+handlemouse(Mouse mouse)
+{
+	Point c;
+	double x, y, v;
+
+	MouseGlobalPosition = mouse.xy;
+	MouseRelativePosition = subpt(mouse.xy, screen->r.min);
+	c = MouseRelativePosition;
+	c.x -= Dx(screen->r)/2.0;
+	c.y -= Dy(screen->r)/2;
+	x = ((double)c.x)/(Dx(screen->r)/2);
+	y = ((double)c.y)/(Dy(screen->r)/2);
+	MouseRadius = sqrt(pow(x, 2) + pow(y, 2));
+	MouseAngle = atan2(-y, x);
+	
+	Hue = -MouseAngle + 2*PI;
+	if (Hue > 2*PI) {
+		Hue -= 2*PI;
 	}
 
-	VirtualWindow = allocimage(display, screen->r, RGBA32, 0, DTransparent);
-	if (VirtualWindow == nil) {
-		sysfatal("initcanvas: %r");
+	MouseHueRadiusStart = RADIUS * (1+COLORPICKERPADDING);
+	MouseHueRadiusEnd = MouseHueRadiusStart + (RADIUS * COLORPICKERRADIUS);
+	MouseInHue = MouseRadius >= MouseHueRadiusStart && MouseRadius <= MouseHueRadiusEnd;
+	MouseInGradient = MouseRadius <= RADIUS;
+	
+	ColorUnderMouse = pickcolor();
+	if (MouseInGradient && mouse.buttons & 0x01) {
+		Color = ColorUnderMouse;
+		print("%08x\n", Color);
 	}
 
- 	rc = resizeimage(VirtualWindow, HuePicker);
- 	if (rc < 0) {
- 		sysfatal("resizeimage: %r");
- 	}
+	if (MouseInHue && mouse.buttons & 0x01) {
+		HueStart = Hue;
+		UpdateGradient = 1;
+		UpdateCanvas = 1;
+		ShouldDraw = 1;
+	}
+	
+	v = Value;
+	if (mouse.buttons & 0x08) {
+		v += VALUEINCREASE;
+	}
+	if (mouse.buttons & 0x16) {
+		v -= VALUEINCREASE;
+	}
+	if (v != Value) {
+		if (v > 1.0) {
+			v = 1.0;
+		}
+		if (v < 0.0) {
+			v = 0.0;
+		}
+		Value = v;
+		UpdateGradient = 1;
+		UpdateCanvas = 1;
+		ShouldDraw = 1;
+	}
 
- 	rc = resizeimage(VirtualWindow, Gradient);
- 	if (rc < 0) {
- 		sysfatal("resizeimage: %r");
- 	}
-
-	setbackground(BACKGROUNDCOLOR);
-	drawcanvas();
+	updatecolorindicator();
 }
 
 void
@@ -360,16 +512,21 @@
 
 	inithuepicker();
 	initgradient();
-	setgradienthue();
 
 	einit(Emouse | Ekeyboard);
 	initcanvas();
 	for (;RunApp;) {
+		setgradienthue();
+		updatecanvas();
+		drawcanvas();
 		switch(event(&e)) {
 		case Ekeyboard:
 			if (e.kbdc == 'q') {
 				RunApp = 0;
 			}
+			break;
+		case Emouse:
+			handlemouse(e.mouse);
 			break;
 		}
 	}
--