summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McDermott <patrick.mcdermott@libiquity.com>2019-10-13 20:54:32 (EDT)
committer Patrick McDermott <patrick.mcdermott@libiquity.com>2019-10-13 20:54:32 (EDT)
commit351ba155fdf7db739f45f9d4381f0b979d9037ab (patch)
treef8e7685dec21526de0e859547e0c10f167d9504d
parentbb65b69a5b97f9f5508f4fa5adbdc19b480ee638 (diff)
downloadtimeteller-351ba155fdf7db739f45f9d4381f0b979d9037ab.zip
timeteller-351ba155fdf7db739f45f9d4381f0b979d9037ab.tar.gz
timeteller-351ba155fdf7db739f45f9d4381f0b979d9037ab.tar.bz2
clock_*(): New functions
And create and draw the clock on the screen.
-rw-r--r--src/clock.c198
-rw-r--r--src/clock.h44
-rw-r--r--src/local.mk2
-rw-r--r--src/main.c1
-rw-r--r--src/screen.c18
5 files changed, 262 insertions, 1 deletions
diff --git a/src/clock.c b/src/clock.c
new file mode 100644
index 0000000..0e6085c
--- /dev/null
+++ b/src/clock.c
@@ -0,0 +1,198 @@
+/*
+ * Clock screen functions
+ *
+ * Copyright (C) 2019 Patrick McDermott
+ *
+ * This file is part of Timeteller.
+ *
+ * Timeteller is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Timeteller is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Timeteller. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "clock.h"
+
+#include <assert.h>
+#include <curses.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "screen.h"
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#define NUM_DIGITS 6
+#define NUM_COLONS 2
+#define DIGIT_HEIGHT 5
+#define DIGIT_WIDTH 3
+#define COLON_WIDTH 1
+#define SPACING 1
+
+static const uint16_t _clock_font[] = {
+ 075557, /* 0 */
+ 011111, /* 1 */
+ 071747, /* 2 */
+ 071717, /* 3 */
+ 055711, /* 4 */
+ 074717, /* 5 */
+ 074757, /* 6 */
+ 071111, /* 7 */
+ 075757, /* 8 */
+ 075717, /* 9 */
+ 004040, /* : */
+};
+#define COLON_DIGIT 10
+
+struct clock {
+ WINDOW *win;
+ int begy;
+ int begx;
+ int font_size;
+};
+
+struct clock *
+clock_new(WINDOW *win)
+{
+ struct clock *clock;
+
+ clock = calloc(1, sizeof(*clock));
+ if (clock == NULL) {
+ return NULL;
+ }
+
+ if (clock_size(clock) == false) {
+ free(clock);
+ return NULL;
+ }
+
+ clock->win = win;
+
+ return clock;
+}
+
+bool
+clock_size(struct clock *clock)
+{
+ int win_h;
+ int win_w;
+ int clock_h;
+ int clock_w;
+
+ assert(clock);
+
+ getmaxyx(clock->win, win_h, win_w);
+ if (win_h < 0 && win_w < 0) {
+ win_h = LINES;
+ win_w = COLS;
+ }
+ clock_h = DIGIT_HEIGHT + SPACING * 2;
+ clock_w = NUM_DIGITS * (DIGIT_WIDTH + SPACING)
+ + NUM_COLONS * (COLON_WIDTH + SPACING)
+ + SPACING;
+ clock_w *= 2; /* A "dot" is two columns wide. */
+ if (win_h < clock_h || win_w < clock_w) {
+ return false;
+ }
+ clock->font_size = MIN(win_h / clock_h, win_w / clock_w);
+ clock_h *= clock->font_size;
+ clock_w *= clock->font_size;
+ clock->begy = (win_h - clock_h ) / 2;
+ clock->begx = (win_w - clock_w + 1) / 2;
+
+ return true;
+}
+
+/* begy and begx are measured in dots from the top left corner of clock area. */
+static void
+_clock_draw_dot(struct clock *clock, int begy, int begx, int dot)
+{
+ chtype ch;
+ int y;
+ int x;
+
+ assert(clock);
+
+ ch = ' ' | (dot ? A_REVERSE : 0);
+
+ begy = clock->begy + begy * clock->font_size;
+ begx = clock->begx + (begx * clock->font_size) * 2;
+ for (y = 0; y < clock->font_size; ++y) {
+ for (x = 0; x < clock->font_size; ++x) {
+ mvwaddch(clock->win, begy + y, begx + x * 2 , ch);
+ mvwaddch(clock->win, begy + y, begx + x * 2 + 1, ch);
+ }
+ }
+}
+
+/* begx is measured in dots from the left side of clock area. */
+static void
+_clock_draw_digit(struct clock *clock, int begx, int d)
+{
+ int i;
+ int y;
+ int x;
+ int dot;
+
+ assert(clock);
+
+ for (i = 0; i < DIGIT_HEIGHT * DIGIT_WIDTH; ++i) {
+ y = 1 + i / DIGIT_WIDTH;
+ x = begx + i % DIGIT_WIDTH;
+ dot = _clock_font[d] & (1 << (DIGIT_HEIGHT*DIGIT_WIDTH-1-i));
+ _clock_draw_dot(clock, y, x, dot);
+ }
+}
+
+void
+clock_draw(struct clock *clock)
+{
+ time_t t = 0;
+ struct tm *tm;
+ int x;
+
+ assert(clock);
+
+ time(&t);
+ if (t < (time_t) 0) {
+ return;
+ }
+
+ tm = localtime(&t);
+ if (tm == NULL) {
+ return;
+ }
+
+ x = 0;
+ _clock_draw_digit(clock, x += SPACING , tm->tm_hour / 10);
+ _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, tm->tm_hour % 10);
+ _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, COLON_DIGIT);
+ _clock_draw_digit(clock, x += SPACING + COLON_WIDTH, tm->tm_min / 10);
+ _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, tm->tm_min % 10);
+ _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, COLON_DIGIT);
+ _clock_draw_digit(clock, x += SPACING + COLON_WIDTH, tm->tm_sec / 10);
+ _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, tm->tm_sec % 10);
+}
+
+struct clock *
+clock_destroy(struct clock **clock_p)
+{
+ struct clock *clock;
+
+ assert(clock_p && *clock_p);
+
+ clock = *clock_p;
+
+ free(clock);
+ return clock = NULL;
+}
diff --git a/src/clock.h b/src/clock.h
new file mode 100644
index 0000000..eedda1c
--- /dev/null
+++ b/src/clock.h
@@ -0,0 +1,44 @@
+/*
+ * Clock screen functions
+ *
+ * Copyright (C) 2019 Patrick McDermott
+ *
+ * This file is part of Timeteller.
+ *
+ * Timeteller is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Timeteller is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Timeteller. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CLOCK_H_
+#define CLOCK_H_
+
+#include <curses.h>
+#include <stdbool.h>
+
+#include "screen.h"
+
+struct clock;
+
+struct clock *
+clock_new(WINDOW *win);
+
+bool
+clock_size(struct clock *clock);
+
+void
+clock_draw(struct clock *clock);
+
+struct clock *
+clock_destroy(struct clock **clock_p);
+
+#endif /* CLOCK_H_ */
diff --git a/src/local.mk b/src/local.mk
index d9142ac..0429b52 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -1,4 +1,6 @@
timeteller_SOURCES += \
+ %reldir%/clock.c \
+ %reldir%/clock.h \
%reldir%/main.c \
%reldir%/screen.c \
%reldir%/screen.h \
diff --git a/src/main.c b/src/main.c
index 673dd24..a3118db 100644
--- a/src/main.c
+++ b/src/main.c
@@ -67,6 +67,7 @@ main(int argc, char **argv)
screen = screen_new();
+ screen_draw(screen);
speech_play_time(speech);
screen_destroy(&screen);
diff --git a/src/screen.c b/src/screen.c
index a8b8b26..f705701 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -25,8 +25,11 @@
#include <curses.h>
#include <stdlib.h>
+#include "clock.h"
+
struct screen {
- WINDOW *win;
+ WINDOW *win;
+ struct clock *clock;
};
struct screen *
@@ -46,12 +49,23 @@ screen_new(void)
}
curs_set(0); /* Ignore errors. */
+ screen->clock = clock_new(screen->win);
+ if (screen->clock == NULL) {
+ free(screen);
+ return NULL;
+ }
+
return screen;
}
void
screen_draw(struct screen *screen)
{
+ assert(screen);
+
+ clock_draw(screen->clock);
+
+ refresh();
}
struct screen *
@@ -66,6 +80,8 @@ screen_destroy(struct screen **screen_p)
delwin(screen->win);
endwin();
+ clock_destroy(&screen->clock);
+
free(screen);
return screen = NULL;
}