/*
* 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, /* : */
};
#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;
}