ref: 13590f759547f4ef544b251f2966b4ed2d82038c
dir: /eentercolor.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <event.h> #include <keyboard.h> /* KNOWN BUGS First pixel row of the image doesn't yield proper values. */ typedef struct Hsv Hsv; typedef struct Rgb Rgb; struct Hsv { double h; double s; double v; }; struct Rgb { double r; double g; double b; }; static Rgb hsv2rgb(Hsv hsv) { Rgb r; int i; double ff, p, q, t; if (hsv.s <= 0.) { r.r = hsv.v; r.g = hsv.v; r.b = hsv.v; return r; } hsv.h *= 360.; if (hsv.h >= 360.0) hsv.h = 0.; hsv.h /= 60.; i = hsv.h; ff = hsv.h - i; p = hsv.v * (1.0 - hsv.s); q = hsv.v * (1.0 - (hsv.s * ff)); t = hsv.v * (1.0 - (hsv.s * (1.0 - ff))); switch (i) { case 0: r.r = hsv.v; r.g = t; r.b = p; break; case 1: r.r = q; r.g = hsv.v; r.b = p; break; case 2: r.r = p; r.g = hsv.v; r.b = t; break; case 3: r.r = p; r.g = q; r.b = hsv.v; break; case 4: r.r = t; r.g = p; r.b = hsv.v; break; case 5: default: r.r = hsv.v; r.g = p; r.b = q; break; } return r; } static Image *colors = nil; static uchar *data; static void initimage(double hue) { uchar *d; int x, y, n; Hsv hsv; Rgb rgb; n = 100 * 100 * 4*sizeof(uchar); if (!data) data = malloc(n); if (!colors) colors = allocimage(display, Rect(0, 0, 100, 100), RGBA32, 0, DNofill); if (!colors || !data) sysfatal("out of memory: %r"); hsv.h = hue; for (y = 0; y < 100; y++) for (x = 0; x < 100; x++) { d = data + (y*100 + x)*4*sizeof(uchar); hsv.s = (double)x/100; hsv.v = 1.-(double)y/100; rgb = hsv2rgb(hsv); d[0] = 255; d[1] = rgb.b * 255; d[2] = rgb.g * 255; d[3] = rgb.r * 255; } loadimage(colors, colors->r, data, n); } static Image *huegrad = nil; static void inithuegrad(void) { uchar *dat, *d; int x, n, p; Rgb rgb; Hsv hsv; if (!huegrad) huegrad = allocimage(display, Rect(0, 0, 100, 1), RGBA32, 1, DNofill); if (!huegrad) sysfatal("out of memory: %r"); p = huegrad->depth/8; n = 100 * p; dat = malloc(n); if (!dat) sysfatal("out of memory: %r"); hsv.v = 1.; hsv.s = 1.; for (x = 0; x < 100; x++) { d = dat + x*p; hsv.h = (double)x/100; rgb = hsv2rgb(hsv); d[0] = 255; d[1] = rgb.b * 255; d[2] = rgb.g * 255; d[3] = rgb.r * 255; } loadimage(huegrad, huegrad->r, dat, n); free(dat); } static Rgb parsergb(char *str) { Rgb rgb; ulong c; uchar *p; char *s; /* valid formats are: (spaces ignored) (RRR,GGG,BBB) RRR,GGG,BBB #RRGGBB */ while (*str == ' ' || *str == '\t') str++; switch (*str) { case '#': str++; c = strtoul(str, nil, 16); p = (uchar*)&c; rgb.r = (double)p[2] / 255; rgb.g = (double)p[1] / 255; rgb.b = (double)p[0] / 255; return rgb; case '(': str++; } rgb.r = (double)strtol(str, &s, 10) / 255; str = s+1; rgb.g = (double)strtol(str, &s, 10) / 255; str = s+1; rgb.b = (double)strtol(str, &s, 10) / 255; return rgb; } static double hue = 0.; int eentercolor(char *ask, ulong *out, Mouse *m) { Event ev; int e; Rectangle r, ri, rh, rc, ro; Point askp, outp; Point xy; uchar *pixel; int fy; Rgb rgb; Hsv hsv; Image *blitimg; Image *selcol; char buf[1 + 3 + 1 + 3 + 1 + 3 + 1 + 1]; /* (XXX,XXX,XXX) */ if (!ask) ask = "color:"; fy = stringsize(font, "M").y; buf[0] = 0; if (!huegrad) inithuegrad(); initimage(hue); pixel = (uchar*)out; /* dimensions of full box */ r.min = m->xy; r.max = addpt(r.min, Pt(110, 110)); r.max.y += 2 * (fy + 10); /* two lines of text */ r.max.y += 15; /* value gradient */ /* dimensions of inline image */ ri = r; ri.min.y += fy + 10; ri.min.x += 5; ri.min.y += 5; ri.max.x = ri.min.x + 100; ri.max.y = ri.min.y + 100; /* dimensions of hue image */ rh.min.x = ri.min.x; rh.min.y = ri.max.y; rh.max.x = ri.max.x; rh.max.y = rh.min.y + 15; /* dimensions of selected color */ rc.min.x = rh.min.x; rc.min.y = rh.max.y; rc.max.x = ri.max.x; rc.max.y = rc.min.y + 15; /* position of ask string */ askp = r.min; askp.x += 5; askp.y += 5; /* position of out string */ outp = rc.min; outp.y += 15 + 5; ro.min = outp; ro.max = addpt(outp, Pt(100, fy)); r.max.x = r.min.x + 110; r.max.y = outp.y + fy + 10; blitimg = allocimage(display, r, screen->chan, 0, DNofill); draw(blitimg, blitimg->r, screen, nil, blitimg->r.min); selcol = nil; for (;;) { /* redraw routines */ draw(screen, r, display->white, nil, ZP); border(screen, r, 1, display->black, ZP); string(screen, askp, display->black, ZP, font, ask); string(screen, outp, display->black, ZP, font, buf); draw(screen, ri, colors, nil, ZP); draw(screen, rh, huegrad, nil, ZP); if (selcol) freeimage(selcol); selcol = allocimage(display, rc, RGBA32, 1, *out); draw(screen, rc, selcol, nil, ZP); /* event handling */ e = event(&ev); switch (e) { case Ekeyboard: if (ev.kbdc == Kesc || ev.kbdc == 'q') goto Abort; if (ev.kbdc == '\n') goto Accept; break; case Emouse: if (!ev.mouse.buttons) break; if (ptinrect(ev.mouse.xy, ri)) { xy = subpt(ev.mouse.xy, ri.min); hsv.s = (double)xy.x/100; hsv.v = 1.-(double)xy.y/100; Setcolor: hsv.h = hue; rgb = hsv2rgb(hsv); Setpixel: pixel[3] = rgb.r * 256; pixel[2] = rgb.g * 256; pixel[1] = rgb.b * 256; pixel[0] = 255; snprint(buf, sizeof buf, "%3d,%3d,%3d", pixel[3], pixel[2], pixel[1]); break; } if (ptinrect(ev.mouse.xy, rh)) { xy.x = ev.mouse.xy.x - rh.min.x; hue = ((double)xy.x / 100); initimage(hue); goto Setcolor; } if (ptinrect(ev.mouse.xy, ro)) { if (!eenter("color:", buf, sizeof buf, &ev.mouse)) break; rgb = parsergb(buf); goto Setpixel; } } } Abort: draw(screen, blitimg->r, blitimg, nil, blitimg->r.min); freeimage(blitimg); if (selcol) freeimage(selcol); return 0; Accept: draw(screen, blitimg->r, blitimg, nil, blitimg->r.min); freeimage(blitimg); if (selcol) freeimage(selcol); return 1; }