diff options
-rw-r--r-- | chrono.c | 198 |
1 files changed, 185 insertions, 13 deletions
@@ -4,8 +4,10 @@ #include <draw.h> #include <mouse.h> #include <keyboard.h> +#include <geometry.h> #define HZ2MS(hz) (1000/(hz)) +#define max(a, b) ((a) > (b)? (a): (b)) enum { Stop, @@ -17,7 +19,7 @@ typedef struct Stopwatch Stopwatch; struct Stopwatch { uvlong elapsed; /* in ms */ - char hms[4][4]; + char hms[3][6+1]; /* HH MM SS.ss */ int state; void (*start)(Stopwatch*); @@ -27,7 +29,10 @@ struct Stopwatch void (*draw)(Stopwatch*, Image*, Point, double); }; +Rectangle UR = {0,0,1,1}; char deffont[] = "/lib/font/bit/lucida/unicode.32.font"; +Image *d7bg, *d7fg; +int d7scale = 60; Image *screenb; Keyboardctl *kc; @@ -37,6 +42,165 @@ Stopwatch *chrono; uvlong nanosec(void); +static Image * +eallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong col) +{ + Image *i; + + i = allocimage(d, r, chan, repl, col); + if(i == nil) + sysfatal("allocimage: %r"); + return i; +} + +/* + * 7-segment display interface + * + * A + * ---- + * | | B + * F | G | + * ---- + * | | C + * E | | + * ---- [] H + * D + * + * bits: 7 6 5 4 3 2 1 0 + * func: H G F E D C B A + */ +static Point +d7(Image *dst, Point dp, uchar bits, int scale, Image *fg, Image *bg) +{ + enum { TV, TH, TD, NSEGS }; + struct { + Point2 poly[6]; + Point pts[6+1]; + int npts; + } segs[NSEGS] = { /* segment parameters */ + [TV] { .poly = { + { 1, 0, 1 }, + { 1.5, 1, 1 }, + { 1.5, 5, 1 }, + { 1, 6, 1 }, + { 0.5, 5, 1 }, + { 0.5, 1, 1 }, + }, .npts = 6+1 }, + [TH] { .npts = 6+1 }, + [TD] { .poly = { + { 0, 0, 1 }, + { 1, 0, 1 }, + { 1, 1, 1 }, + { 0, 1, 1 }, + }, .npts = 4+1 }, + }; + struct { + Point p; + int segtype; + } loc[8] = { /* segment locations (layout) */ + { 1, 2, TH }, /* A */ + { 6, 1, TV }, /* B */ + { 6, 7, TV }, /* C */ + { 1, 14, TH }, /* D */ + { 0, 7, TV }, /* E */ + { 0, 1, TV }, /* F */ + { 1, 8, TH }, /* G */ + { 8, 13, TD }, /* H (dot) */ + }; + Rectangle bbox = { + { 0, 0 }, + { 9, 14 }, + }; + Point segpt[7]; + double maxlen; + int i, j; + + maxlen = 0; + for(i = 0; i < segs[TV].npts-1; i++) + maxlen = max(maxlen, vec2len(segs[TV].poly[i])); + + bbox.max.x = (double)bbox.max.x/maxlen * scale; + bbox.max.y = (double)bbox.max.y/maxlen * scale; + for(i = 0; i < nelem(loc); i++){ + loc[i].p.x = (double)loc[i].p.x/maxlen * scale; + loc[i].p.y = (double)loc[i].p.y/maxlen * scale; + } + + /* normalize TV and build TH out of it */ + for(i = 0; i < segs[TV].npts-1; i++){ + segs[TV].poly[i] = divpt2(segs[TV].poly[i], maxlen); + segs[TH].poly[i] = Vec2(segs[TV].poly[i].y, -segs[TV].poly[i].x); + + segs[TV].pts[i] = Pt(segs[TV].poly[i].x*scale, segs[TV].poly[i].y*scale); + segs[TH].pts[i] = Pt(segs[TH].poly[i].x*scale, segs[TH].poly[i].y*scale); + } + segs[TH].pts[segs[TH].npts-1] = segs[TH].pts[0]; + segs[TV].pts[segs[TV].npts-1] = segs[TV].pts[0]; + + /* normalize TD */ + for(i = 0; i < segs[TD].npts-1; i++){ + segs[TD].poly[i] = divpt2(segs[TD].poly[i], maxlen); + segs[TD].pts[i] = Pt(segs[TD].poly[i].x*scale, segs[TD].poly[i].y*scale); + } + segs[TD].pts[segs[TD].npts-1] = segs[TD].pts[0]; + + /* paint case */ + bbox = rectaddpt(bbox, addpt(dst->r.min, dp)); + draw(dst, bbox, bg, nil, ZP); + + /* paint segments */ + for(i = 0; i < nelem(loc); i++){ + if((bits & 1<<i) == 0) + continue; + + for(j = 0; j < segs[loc[i].segtype].npts-1; j++){ + segpt[j] = addpt(segs[loc[i].segtype].pts[j], loc[i].p); + segpt[j] = addpt(segpt[j], bbox.min); + } + segpt[segs[loc[i].segtype].npts-1] = segpt[0]; + + fillpoly(dst, segpt, segs[loc[i].segtype].npts, 0, fg, ZP); + } + + return Pt(bbox.max.x + 1, bbox.min.y); +} + +static Point +string7(Image *dst, Point dp, char *s, int scale, Image *fg, Image *bg) +{ + static struct { + char c; + uchar bits; + } dmap[] = { + '0', 0x3F, + '1', 0x06, + '2', 0x5B, + '3', 0x4F, + '4', 0x66, + '5', 0x6D, + '6', 0x7D, + '7', 0x07, + '8', 0x7F, + '9', 0x6F, + }; + uchar bits; + int i; + + if(s == nil) + return dp; + + for(; *s != 0; s++) + for(i = 0; i < nelem(dmap); i++) + if(dmap[i].c == *s){ + bits = dmap[i].bits; + if(s[1] == '.') + bits |= 0x80; + dp = d7(dst, dp, bits, scale, fg, bg); + break; + } + return dp; +} + static void stopwatch_start(Stopwatch *self) { @@ -73,20 +237,20 @@ stopwatch_update(Stopwatch *self, uvlong dt) t *= 60; HMS[2] = t; t -= HMS[2]; t *= 1000; HMS[3] = t; - for(i = 0; i < nelem(HMS); i++) - snprint(self->hms[i], sizeof self->hms[i], i < 3? "%02d": "%03d", HMS[i]); + for(i = 0; i < nelem(HMS)-2; i++) + snprint(self->hms[i], sizeof self->hms[i], "%02d", HMS[i]); + snprint(self->hms[i], sizeof self->hms[i], "%02d.%03d", HMS[i], HMS[i+1]); } static void stopwatch_draw(Stopwatch *self, Image *dst, Point dp, double scale) { - USED(scale); int i; for(i = 0; i < nelem(self->hms); i++){ - if(i > 0) - dp = string(dst, dp, display->white, ZP, font, i < 3? ":": "."); - dp = string(dst, dp, display->white, ZP, font, self->hms[i]); + if(i > 0 && i < 3) + dp.x += scale/3; + dp = string7(dst, dp, self->hms[i], scale, d7fg, d7bg); } } @@ -131,6 +295,7 @@ mkstopwatch(void) s->update = stopwatch_update; s->draw = stopwatch_draw; + s->update(s, 0); proccreate(timer, s, mainstacksize); return s; @@ -148,16 +313,14 @@ initscreenb(void) if(screenb != nil) freeimage(screenb); - screenb = allocimage(display, rectsubpt(screen->r, screen->r.min), screen->chan, 0, DNofill); - if(screenb == nil) - sysfatal("allocimage: %r"); + screenb = eallocimage(display, rectsubpt(screen->r, screen->r.min), screen->chan, 0, DNofill); } void redraw(void) { draw(screenb, screenb->r, display->black, nil, ZP); - chrono->draw(chrono, screenb, Pt(10, 10), 1); + chrono->draw(chrono, screenb, Pt(10, 10), d7scale); draw(screen, screen->r, screenb, nil, ZP); flushimage(display, 1); } @@ -173,9 +336,14 @@ resize(void) } void -mouse(Mousectl *) +mouse(Mousectl *mc) { - + if(mc->buttons & 8) + d7scale += 2; + if(mc->buttons & 16) + d7scale -= 2; + if(mc->buttons != 0) + nbsend(drawc, nil); } void @@ -211,6 +379,7 @@ threadmain(int argc, char *argv[]) { Rune r; + GEOMfmtinstall(); ARGBEGIN{ default: usage(); }ARGEND; @@ -222,6 +391,9 @@ threadmain(int argc, char *argv[]) if((kc = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); + d7bg = eallocimage(display, UR, XRGB32, 1, 0x333333FF); + d7fg = eallocimage(display, UR, XRGB32, 1, DRed); + initscreenb(); drawc = chancreate(sizeof(void*), 1); nbsend(drawc, nil); |