aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chrono.c198
1 files changed, 185 insertions, 13 deletions
diff --git a/chrono.c b/chrono.c
index 26750b4..1a3de69 100644
--- a/chrono.c
+++ b/chrono.c
@@ -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);