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;
}
}
--
⑨