shithub: clock

ref: 6670406eb7bc3a815fe16a71b41a3cf265689fa7
dir: clock/clock.c

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>

Point
circlept(Point c, int r, int degrees)
{
 double rad = (double)degrees * PI / 180.0;

 c.x += cos(rad) * r;
 c.y -= sin(rad) * r;
 return c;
}

void
lineb(Image* dst, Point p0, Point p1, Image* src)
{
 int dx = abs(p1.x - p0.x), sx = p0.x < p1.x ? 1 : -1;
 int dy = -abs(p1.y - p0.y), sy = p0.y < p1.y ? 1 : -1;
 int err = dx + dy, e2;

 for(;;) {
  draw(dst, Rect(p0.x, p0.y, p0.x + 1, p0.y + 1), src, nil, ZP);
  if(p0.x == p1.x && p0.y == p1.y)
   break;
  e2 = 2 * err;
  if(e2 >= dy) {
   err += dy;
   p0.x += sx;
  }
  if(e2 <= dx) {
   err += dx;
   p0.y += sy;
  }
 }
}

void
redraw(Image* dst)
{
 Point size = subpt(screen->r.max, screen->r.min);
 Point center = divpt(size, 2);
 Rectangle frame = (Rectangle){Pt(0, 0), size};
 int pad = 10;
 int rad = ((size.x < size.y ? size.x : size.y) / 2) - 2;
 int range = rad - pad;
 Image* view = allocimage(display, frame, screen->chan, 1, 0x000000FF);
 Image* secclr = allocimagemix(display, DRed, DRed);

 for(int i = 0; i < 60; i++) {
  int len = i % 15 == 0 ? range : i % 5 == 0 ? rad - pad / 2 : rad - pad / 3;
  lineb(view, circlept(center, len, i * 6), circlept(center, rad, i * 6), display->white);
 }

 Tm tms = *localtime(time(0));
 int anghr = 90 - (tms.hour * 5 + tms.min / 12) * 6;
 int angmin = 90 - tms.min * 6;
 int angsec = 90 - tms.sec * 6;
 int angsecrev = 270 - tms.sec * 6;

 fillellipse(view, center, rad - pad, rad - pad, display->black, ZP);
 lineb(view, center, circlept(center, range * 0.7, anghr), display->white);
 lineb(view, center, circlept(center, range - 2, angmin), display->white);
 lineb(view, center, circlept(center, range - 2, angsec), secclr);
 lineb(view, center, circlept(center, range * 0.1, angsecrev), secclr);
 fillellipse(view, center, 2, 2, secclr, ZP);

 /* collapse when horizontal window */
 if(size.y > size.x + 2 * pad) {
  /* time */
  char timestr[9];
  snprint(timestr, sizeof(timestr), "%02d:%02d:%02d", tms.hour, tms.min, tms.sec);
  Point timesize = stringsize(display->defaultfont, timestr);
  Point timept = Pt(pad, pad);
  /* date */
  char datestr[30];
  snprint(datestr, sizeof(datestr), "%s", ctime(time(0)));
  datestr[10] = '\0';
  Point datesize = stringsize(display->defaultfont, datestr);
  Point datept = Pt(size.x - datesize.x - pad, pad);
  /* draw */
  draw(view,
       (Rectangle){timept, addpt(timept, Pt(size.x - pad * 2, 0))},
       display->black, nil, ZP);
  string(view, timept, display->white, ZP, display->defaultfont, timestr);
  if(timesize.x + datesize.x < size.x - pad - pad)
   string(view, datept, display->white, ZP, display->defaultfont, datestr);
 }

 draw(dst, screen->r, view, nil, ZP);
 flushimage(display, 1);
 freeimage(secclr);
 freeimage(view);
}

void
eresized(int new)
{
 if(new&& getwindow(display, Refnone) < 0)
  fprint(2, "can't reattach to window");
 redraw(screen);
}

void
main(int argc, char* argv[])
{
 USED(argc, argv);
 
 Event e;
 Mouse m;
 Menu menu;
 char* mstr[] = {"exit", 0};
 int key, timer, t = 1000;

 if(initdraw(0, 0, "clock") < 0)
  sysfatal("initdraw failed");

 eresized(0);
 einit(Emouse);
 timer = etimer(0, t);
 menu.item = mstr;
 menu.lasthit = 0;

 for(;;) {
  key = event(&e);
  if(key == Emouse) {
   m = e.mouse;
   if(m.buttons & 4) {
    if(emenuhit(3, &m, &menu) == 0)
     exits(0);
   }
  } else if(key == timer) {
   redraw(screen);
  }
 }
}