7 #define initstate muginitstate
9 typedef struct State State;
20 typedef struct Face Face;
27 double GAMMA = 1.0; /* theory tells me this should be 2.2, but 1.0 sure looks better */
52 sysfatal("malloc %lud fails", sz);
62 Image *ramp, *small, *osmall, *tmp8, *red, *green, *blue;
66 Rectangle rbig, rramp, rface[nelem(face)], rsmall;
76 rramp.min = addpt(r.min, Pt(4,4));
77 rramp.max = addpt(rramp.min, Pt(256,256));
79 rbig.min = Pt(rramp.max.x+6, rramp.min.y);
80 rbig.max = addpt(rbig.min, Pt(Dx(orig->r), Dy(orig->r)));
83 fr[i] = rectaddpt(Rect(0,0,48,48), Pt(rramp.min.x+48+56*(i%3), rramp.max.y+6+56*(i/3)));
97 g = (double)y / 128.0;
98 return 0.5+g*g; /* gamma from 0.5 to 4.5, with 1.0 near the middle */
105 return (int)(128.0*sqrt(g)+0.5);
112 border(screen, rsmall, -3, blue, ZP);
113 draw(screen, rsmall, small, nil, ZP);
116 border(screen, rface[i], -1, display->black, ZP);
118 draw(screen, rface[i], face[i]->small, nil, ZP);
120 draw(screen, rface[i], display->white, nil, ZP);
124 drawrampbar(Image *color, State *s)
130 draw(screen, br, ramp, nil, subpt(br.min, rramp.min));
133 r.max.x = r.min.x + (int)(s->white*255.0);
134 r.min.x += (int)(s->black*255.0);
135 r.min.y += gamma2y(s->gamma);
138 draw(screen, r, color, nil, ZP);
145 r.min.x += Dx(liner)/3;
146 r.max.x -= Dx(liner)/3;
148 draw(screen, r, color, nil, ZP);
154 draw(screen, r, color, nil, ZP);
160 draw(screen, r, color, nil, ZP);
165 drawscreen(int clear)
171 draw(screen, screen->r, bkgd, nil, ZP);
174 border(screen, rbig, -1, display->black, ZP);
175 draw(screen, rbig, orig, nil, orig->r.min);
177 border(screen, rramp, -1, display->black, ZP);
178 draw(screen, rramp, ramp, nil, ramp->r.min);
179 drawrampbar(red, &state);
181 border(screen, rectaddpt(state.selr, subpt(rbig.min, orig->r.min)), -2, red, ZP);
184 for(i=0; i<nelem(face); i++)
190 moveframe(Rectangle old, Rectangle new)
192 border(screen, rectaddpt(old, subpt(rbig.min, orig->r.min)), -2, orig, old.min);
193 border(screen, rectaddpt(new, subpt(rbig.min, orig->r.min)), -2, red, ZP);
198 * Initialize gamma ramp; should dither for
199 * benefit of non-true-color displays.
209 for(y=0; y<256; y++) {
212 dat[k++] = 255.0 * pow(x/255.0, g);
214 assert(k == sizeof dat);
216 ramp = allocimage(display, Rect(0,0,256,256), GREY8, 0, DNofill);
218 sysfatal("allocimage: %r");
220 if(loadimage(ramp, ramp->r, dat, sizeof dat) != sizeof dat)
221 sysfatal("loadimage: %r");
229 for(i=0; i<256; i++) {
237 changestretch(double stretch)
239 state.stretch = stretch;
243 * There is greyscale data for the rectangle datar in data;
244 * extract square r and write it into the 48x48 pixel image small.
247 process(double *data, Rectangle datar, Rectangle r, Image *small)
249 double black, center, delta, *k, shrink, sum, *tmp[48], *tt, w, white, x;
250 int datadx, dp, dx, dy, error, i, ii, j, jj;
251 int ksize, ksizeby2, sdata[48*48], sd, sh, sm, sv, u, uu, uuu, v, vv;
259 ksize = 1+2*(int)(shrink/2.0);
263 k = emalloc(ksize*sizeof(k[0]));
266 for(i=1; i<ksize-1; i++)
270 x = shrink - floor(shrink);
275 for(i=0; i<ksize; i++)
278 for(i=0; i<ksize; i++)
284 tmp[i] = emalloc(datadx*sizeof(tmp[i][0]));
286 /* squeeze vertically */
287 for(i=0; i<48; i++) {
288 ii = r.min.y+i*dy/48;
291 for(j=r.min.x-ksize; j<r.max.x+ksize; j++) {
292 if(j<datar.min.x || j>=datar.max.x)
297 if(uu>=datar.min.y && uu+ksize<datar.max.y)
298 for(u=0; u<ksize; u++){
303 for(u=0; u<ksize; u++){
304 if(uu+u>=datar.min.y && uu+u<datar.max.y)
308 tt[j-datar.min.x] = w;
312 /* stretch value scale */
313 center = (state.black+state.white)/2;
314 delta = state.stretch*(state.white-state.black)/2;
315 black = center - delta;
316 white = center + delta;
318 /* squeeze horizontally */
319 for(i=0; i<48; i++) {
321 for(j=0; j<48; j++) {
322 jj = r.min.x+j*dx/48;
324 for(v=0; v<ksize; v++) {
325 vv = jj - ksizeby2 + v;
326 if(vv<datar.min.x || vv>=datar.max.x) {
327 w += k[v]; /* assume white surround */
330 w += k[v]*tt[vv-datar.min.x];
332 if(w < black || black==white)
337 w = (w-black)/(white-black);
338 sdata[i*48+j] = state.gtab[(int)(1000.0*w)];
342 /* dither to lower depth before copying into GREY8 version */
343 if(small->chan != GREY8) {
346 for(i=0; i<48; i++) {
347 sm = 0xFF ^ (0xFF>>dp);
350 for(j=0; j<48; j++) {
352 sd = clamp[sdata[ii]+256];
362 /* propagate error, with decay (sum errors < 1) */
364 if(ii+49 < 48*48) { /* one test is enough, really */
365 sdata[ii+1] = sdata[ii+1]+((3*error)>>4);
366 sdata[ii+48] = sdata[ii+48]+((3*error)>>4);
367 sdata[ii+49] = sdata[ii+49]+((3*error)>>3);
370 /* produce correct color map value by copying bits */
382 for(i=0; i<nelem(bdata); i++)
384 if(loadimage(tmp8, tmp8->r, bdata, sizeof bdata) != sizeof bdata)
385 sysfatal("loadimage: %r");
386 draw(small, small->r, tmp8, nil, tmp8->r.min);
388 for(i=0; i<nelem(bdata); i++)
390 if(loadimage(small, small->r, bdata, sizeof bdata) != sizeof bdata)
391 sysfatal("loadimage: %r");
405 val2cmap[i] = rgb2cmap(i, i, i);
413 for(i=0; i<=1000; i++)
414 s->gtab[i] = val2cmap[(int)(255.0*pow((i/1000.0), 1.0/s->gamma))];
422 ib = state.black * 255.0;
423 iw = state.white * 255.0;
445 n = allocimage(display, i->r, i->chan, 0, DNofill);
447 sysfatal("allocimage: %r");
449 draw(n, n->r, i, nil, i->r.min);
461 n = allocimage(display, i->r, GREY8, 0, DNofill);
463 sysfatal("allocimage: %r");
465 draw(n, n->r, i, nil, i->r.min);
489 process(rdata, orig->r, state.selr, small);
495 saveface(Face *f, int slot)
500 small = copyimage(f->small);
507 face[slot] = emalloc(sizeof(*face[slot]));
509 freeimage(face[slot]->small);
510 face[slot]->small = nil;
514 face[slot]->small = copyimage(small);
515 face[slot]->state = state;
517 face[slot]->small = copyimage(f->small);
518 face[slot]->state = f->state;
524 writeface(char *outfile, Image *image)
532 if((fd = create(outfile, OWRITE, 0666)) < 0)
536 switch(image->chan) {
542 if(unloadimage(image, image->r, data, 48*48/8) != 48*48/8)
543 sysfatal("unloadimage: %r");
544 for(y=0; y<48; y++) {
546 fprint(fd, "0x%.2x%.2x,", data[y*6+i*2+0], data[y*6+i*2+1]);
553 if(unloadimage(image, image->r, data, 48*48/4) != 48*48/4)
554 sysfatal("unloadimage: %r");
555 for(y=0; y<48; y++) {
557 fprint(fd, "0x%.2x%.2x,%.2x%.2x,",
558 data[y*12+i*4+0], data[y*12+i*4+1],
559 data[y*12+i*4+2], data[y*12+i*4+3]);
567 rv = writeimage(fd, image, 0); /* dolock? */
577 room(Rectangle out, Rectangle in, int *a)
579 a[Left] = out.min.x - in.min.x;
580 a[Right] = out.max.x - in.max.x;
581 a[Top] = out.min.y - in.min.y;
582 a[Bottom] = out.max.y - in.max.y;
602 move(Rectangle r, Rectangle picr, Point d, int k, Rectangle *rp)
613 if(i>=Dx(r) || i>=Dy(r))
624 * should really check i/2, but this is safe and feedback
625 * makes the control feel right
627 i = -min(-i, a[Right]);
634 /* divide the half bit equally */
638 r.max.x = r.min.x+Dy(r);
641 r.min.x = r.max.x-Dy(r);
646 if(i>=Dx(r) || i>=Dy(r))
648 i = -min(-i, a[Right]);
656 i = -min(-i, a[Bottom]);
663 /* divide the half bit equally */
667 r.max.y = r.min.y+Dx(r);
670 r.min.y = r.max.y-Dx(r);
675 d.x = min(d.x, a[Right]);
677 d.x = max(d.x, a[Left]);
679 d.y = min(d.y, a[Bottom]);
681 d.y = max(d.y, a[Top]);
687 i = min(i, a[Bottom]);
688 i = -max(-i, a[Top]);
690 i = min(i, a[Right]);
694 /* divide the half bit equally */
698 r.max.y = r.min.y+Dx(r);
701 r.min.y = r.max.y-Dx(r);
706 if(i>=Dx(r) || i>=Dy(r))
709 i = -min(-i, a[Bottom]);
716 i = min(i, a[Right]);
717 i = -max(-i, a[Left]);
719 i = min(i, a[Bottom]);
723 /* divide the half bit equally */
727 r.max.x = r.min.x+Dy(r);
730 r.min.x = r.max.x-Dy(r);
735 if(i>=Dx(r) || i>=Dy(r))
737 i = -min(-i, a[Right]);
738 i = -min(-i, a[Bottom]);
743 if(Dx(r)<3 || Dy(r)<3){
748 return !eqrect(r, oldr);
752 rlist(Rectangle r, Rectangle *ra)
757 tr.max.y = r.min.y+Dy(r)/4;
759 ra[0].max.x = tr.min.x+Dx(tr)/4;
761 ra[1].min.x = ra[0].max.x;
762 ra[1].max.x = tr.max.x-Dx(tr)/4;
764 ra[2].min.x = ra[1].max.x;
767 tr.max.y = r.max.y-Dy(r)/4;
769 ra[3].max.x = tr.min.x+Dx(tr)/4;
771 ra[4].min.x = ra[3].max.x;
772 ra[4].max.x = tr.max.x-Dx(tr)/4;
774 ra[5].min.x = ra[4].max.x;
779 ra[6].max.x = tr.min.x+Dx(tr)/4;
781 ra[7].min.x = ra[6].max.x;
782 ra[7].max.x = tr.max.x-Dx(tr)/4;
784 ra[8].min.x = ra[7].max.x;
798 fprint(2, "usage: mug [file.bit]\n");
805 if(new && getwindow(display, Refmesg) < 0)
806 fprint(2,"can't reattach to window");
814 cursor changes while in rbig to indicate region.
815 only button 1 works for resizing region
816 only button 1 works for moving thingy in ramp
818 button-3 menu: Reset, Depth, Undo, Save, Write
823 {0xfe, 0x00, 0x82, 0x00, 0x8c, 0x00, 0x87, 0xff,
824 0xa0, 0x01, 0xb0, 0x01, 0xd0, 0x01, 0x11, 0xff,
825 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00,
826 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x1f, 0x00, },
827 {0x00, 0x00, 0x7c, 0x00, 0x70, 0x00, 0x78, 0x00,
828 0x5f, 0xfe, 0x4f, 0xfe, 0x0f, 0xfe, 0x0e, 0x00,
829 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
830 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, }
835 {0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x06, 0xc0,
836 0x1c, 0x70, 0x10, 0x10, 0x0c, 0x60, 0xfc, 0x7f,
837 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff,
838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
839 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
840 0x03, 0x80, 0x0f, 0xe0, 0x03, 0x80, 0x03, 0x80,
841 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x00, 0x00,
842 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
847 {0x00, 0x7f, 0x00, 0x41, 0x00, 0x31, 0xff, 0xe1,
848 0x80, 0x05, 0x80, 0x0d, 0x80, 0x0b, 0xff, 0x88,
849 0x00, 0x88, 0x0, 0x88, 0x00, 0x88, 0x00, 0x88,
850 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xf8, },
851 {0x00, 0x00, 0x00, 0x3e, 0x00, 0x0e, 0x00, 0x1e,
852 0x7f, 0xfa, 0x7f, 0xf2, 0x7f, 0xf0, 0x00, 0x70,
853 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
854 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, }
859 {0x07, 0xc0, 0x04, 0x40, 0x04, 0x40, 0x04, 0x58,
860 0x04, 0x68, 0x04, 0x6c, 0x04, 0x06, 0x04, 0x02,
861 0x04, 0x06, 0x04, 0x6c, 0x04, 0x68, 0x04, 0x58,
862 0x04, 0x40, 0x04, 0x40, 0x04, 0x40, 0x07, 0xc0, },
863 {0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
864 0x03, 0x90, 0x03, 0x90, 0x03, 0xf8, 0x03, 0xfc,
865 0x03, 0xf8, 0x03, 0x90, 0x03, 0x90, 0x03, 0x80,
866 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, }
871 {0x00, 0xf8, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88,
872 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88,
873 0xff, 0x88, 0x80, 0x0b, 0x80, 0x0d, 0x80, 0x05,
874 0xff, 0xe1, 0x00, 0x31, 0x00, 0x41, 0x00, 0x7f, },
875 {0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
876 0x0, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
877 0x00, 0x70, 0x7f, 0xf0, 0x7f, 0xf2, 0x7f, 0xfa,
878 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x3e, 0x00, 0x00, }
883 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
884 0xff, 0xff, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
885 0xfc, 0x7f, 0x0c, 0x60, 0x10, 0x10, 0x1c, 0x70,
886 0x06, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, },
887 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
888 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe,
889 0x03, 0x80, 0x03, 0x80, 0x0f, 0xe0, 0x03, 0x80,
890 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
895 {0x1f, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00,
896 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00,
897 0x11, 0xff, 0xd0, 0x01, 0xb0, 0x01, 0xa0, 0x01,
898 0x87, 0xff, 0x8c, 0x00, 0x82, 0x00, 0xfe, 0x00, },
899 {0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
900 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
901 0x0e, 0x00, 0x0f, 0xfe, 0x4f, 0xfe, 0x5f, 0xfe,
902 0x78, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x00, 0x0, }
907 {0x03, 0xe0, 0x02, 0x20, 0x02, 0x20, 0x1a, 0x20,
908 0x16, 0x20, 0x36, 0x20, 0x60, 0x20, 0x40, 0x20,
909 0x60, 0x20, 0x36, 0x20, 0x16, 0x20, 0x1a, 0x20,
910 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x03, 0xe0, },
911 {0x00, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
912 0x09, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x3f, 0xc0,
913 0x1f, 0xc0, 0x09, 0xc0, 0x09, 0xc0, 0x01, 0xc0,
914 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, }
919 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
920 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
921 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF,
922 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
923 {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE,
924 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
925 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
926 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00, }
931 Cursor *corners[10] = {
935 nil, /* default arrow */
953 /*BUG make less flashy */
955 moveface(Image *back, Point lastp, Image *face, Point p, Point d)
957 draw(screen, rectaddpt(back->r, subpt(lastp, d)), back, nil, back->r.min);
958 draw(back, back->r, screen, nil, addpt(back->r.min, subpt(p, d)));
959 border(screen, rectaddpt(face->r, subpt(p, d)),
960 -1, display->black, ZP);
961 draw(screen, rectaddpt(face->r, subpt(p, d)),
962 face, nil, face->r.min);
966 dragface(Mouse *m, Image *im, Point d, int x)
973 back = allocimage(display, Rect(-1,-1,49,49), display->image->chan, 0, DNofill);
975 sysfatal("dragface backing store: %r");
979 draw(back, back->r, screen, nil, addpt(back->r.min, subpt(lastp, d)));
980 esetcursor(&clearcursor);
982 moveface(back, lastp, im, m->xy, d);
984 }while(*m=emouse(), m->buttons==1);
986 draw(screen, rectaddpt(back->r, subpt(lastp, d)), back, nil, back->r.min);
989 for(i=0; i<nelem(face); i++)
990 if(ptinrect(m->xy, rface[i]))
992 if(ptinrect(m->xy, rsmall))
996 while(*m=emouse(), m->buttons)
1006 state.stretch = 1.0;
1010 state.selr = insetrect(orig->r, 5);
1011 sdx = Dx(state.selr);
1012 sdy = Dy(state.selr);
1014 state.selr.max.x = state.selr.min.x+sdy;
1016 state.selr.max.y = state.selr.min.y+sdx;
1020 main(int argc, char **argv)
1022 int ccursor, i, fd, k, n, y;
1024 double gammatab[256];
1028 Rectangle nselr, rbig9[9];
1038 if((fd = open(argv[0], OREAD)) < 0)
1039 sysfatal("open %s: %r", argv[0]);
1043 if (initdraw(0, 0, "mug") < 0)
1044 sysfatal("initdraw failed: %r");
1046 if((orig = readimage(display, fd, 0)) == nil)
1047 sysfatal("readimage: %r");
1049 orig = grey8image(orig);
1054 bkgd = allocimagemix(display, DPaleyellow, DWhite);
1055 small = allocimage(display, Rect(0,0,48,48), GREY4, 0, DWhite);
1056 tmp8 = allocimage(display, Rect(0,0,48,48), GREY8, 0, DWhite);
1057 red = allocimage(display, Rect(0,0,1,1), display->image->chan, 1, DRed);
1058 green = allocimage(display, Rect(0,0,1,1), display->image->chan, 1, DGreen);
1059 blue = allocimage(display, Rect(0,0,1,1), display->image->chan, 1, DBlue);
1060 if(bkgd==nil || small==nil || tmp8==nil || red==nil || green==nil || blue==nil)
1061 sysfatal("allocimage: %r");
1063 n = Dx(orig->r)*Dy(orig->r);
1064 data = emalloc(n*sizeof data[0]);
1065 rdata = emalloc(n*sizeof rdata[0]);
1067 if(unloadimage(orig, orig->r, data, n) != n)
1068 sysfatal("unloadimage: %r");
1070 for(i=0; i<256; i++)
1071 gammatab[i] = pow((255-i)/(double)255.0, GAMMA);
1074 rdata[i] = gammatab[255-data[i]];
1077 process(rdata, orig->r, state.selr, small);
1079 flushimage(display, 1);
1080 einit(Emouse|Ekeyboard);
1083 if((n=eread(Emouse|Ekeyboard, &e))==Ekeyboard)
1091 esetcursor(corners[ccursor]);
1092 switch(emenuhit(3, &m, &menu)){
1098 small = allocimage(display, Rect(0,0,48,48), CHAN1(CGrey, state.depth), 0, DWhite);
1100 sysfatal("allocimage: %r");
1101 process(rdata, orig->r, state.selr, small);
1107 /* osmall = small, so no freeimage */
1109 if(state.depth == 0)
1111 small = allocimage(display, Rect(0,0,48,48), CHAN1(CGrey, state.depth), 0, DWhite);
1113 sysfatal("allocimage: %r");
1114 process(rdata, orig->r, state.selr, small);
1121 writeface(nil, small);
1129 if(ptinrect(m.xy, rbig)){
1130 rlist(rectaddpt(state.selr, subpt(rbig.min, orig->r.min)), rbig9);
1132 if(ptinrect(m.xy, rbig9[i]))
1136 esetcursor(corners[ccursor]);
1144 while(m=emouse(), m.buttons&1){
1145 if(move(state.selr, orig->r, subpt(m.xy, lastp), i, &nselr)){
1146 moveframe(state.selr, nselr);
1149 process(rdata, orig->r, state.selr, small);
1157 if(ccursor != 9){ /* default cursor */
1159 esetcursor(corners[ccursor]);
1162 if(ptinrect(m.xy, rramp)){
1166 y = gamma2y(state.gamma);
1167 if(abs(y-(m.xy.y-rramp.min.y)) > 5)
1169 k = section(m.xy.x-rramp.min.x);
1170 drawrampbar(green, &state);
1172 while(m=emouse(), m.buttons&1){
1173 if(!ptinrect(m.xy, rramp))
1179 if((m.xy.x-rramp.min.x)/255.0 < state.white){
1180 state.black = (m.xy.x-rramp.min.x)/255.0;
1185 state.gamma = y2gamma(m.xy.y-rramp.min.y);
1189 if((m.xy.x-rramp.min.x)/255.0 > state.black){
1190 state.white = (m.xy.x-rramp.min.x)/255.0;
1195 state.black += (m.xy.x-lastp.x)/255.0;
1196 state.white += (m.xy.x-lastp.x)/255.0;
1197 state.gamma = y2gamma(p.y);
1200 process(rdata, orig->r, state.selr, small);
1202 drawrampbar(green, &state);
1205 process(rdata, orig->r, state.selr, small);
1207 drawrampbar(red, &state);
1213 if(ptinrect(m.xy, rsmall)){
1216 n=dragface(&m, small, subpt(m.xy, rsmall.min), -1);
1222 for(i=0; i<nelem(face); i++)
1223 if(ptinrect(m.xy, rface[i]))
1225 if(i<nelem(face) && face[i] != nil){
1228 n=dragface(&m, face[i]->small, subpt(m.xy, rface[i].min), i);
1231 saveface(face[i], n);
1237 while(m.buttons==1);