diff options
Diffstat (limited to 'src/clock.c')
-rw-r--r-- | src/clock.c | 198 |
1 files changed, 198 insertions, 0 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; +} |