/* * 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 3 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 . */ #include "clock.h" #include #include #include #include #include #include #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, /* : */ 000000, /* Blank */ }; #define COLON_DIGIT 10 #define BLANK_DIGIT 11 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); } void clock_clear(struct clock *clock) { int x; x = 0; _clock_draw_digit(clock, x += SPACING , BLANK_DIGIT); _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, BLANK_DIGIT); _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, BLANK_DIGIT); _clock_draw_digit(clock, x += SPACING + COLON_WIDTH, BLANK_DIGIT); _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, BLANK_DIGIT); _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, BLANK_DIGIT); _clock_draw_digit(clock, x += SPACING + COLON_WIDTH, BLANK_DIGIT); _clock_draw_digit(clock, x += SPACING + DIGIT_WIDTH, BLANK_DIGIT); } struct clock * clock_destroy(struct clock **clock_p) { struct clock *clock; assert(clock_p && *clock_p); clock = *clock_p; free(clock); return clock = NULL; }