summaryrefslogtreecommitdiff
path: root/src/calendar.cpp
blob: d743718ff75f0d5c514a075c5d0079c65c18a6e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <GxEPD2_BW.h>
#include <Fonts/FreeSansBold12pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <Fonts/FreeSans9pt7b.h>
#include <ctime>

#define CELL_SPACING 10

static const char *week_days[] {
	"Mo", "Di", "Mi", "Do", "Fr", "Sa", "So",
};

static const char *months[] {
	"Januar", "Februar", "Maerz", "April", "Mai", "Juni", "Juli",
	"August", "September", "Oktober", "November", "Dezember",
};

enum month_t {
	JANUARY = 0,
	FEBRUARY,
	MARCH,
	APRIL,
	MAY,
	JUNE,
	JULY,
	AUGUST,
	SEPTEMBER,
	OCTOBER,
	NOVEMBER,
	DECEMBER,
};

static int days_in_month(int month, int year) {
	switch (month) {
		case JANUARY:
		case MARCH:
		case MAY:
		case JULY:
		case AUGUST:
		case OCTOBER:
		case DECEMBER:
			return 31;
		case APRIL:
		case JUNE:
		case SEPTEMBER:
		case NOVEMBER:
			return 30;
		case FEBRUARY:
			if (year % 400 == 0) return 29;
			if (year % 100 == 0) return 28;
			if (year %   4 == 0) return 29;
	}
	assert(month >= 0 && month < 12);
	return 0;
}

/*
 * @display    where to draw on
 * @x0         absolute initial X coord
 * @y0         absolute initial Y coord
 * @w0         width of a cell
 * @h0         height of a cell
 * @xoff       X pos of cell
 * @yoff       Y pos of cell
 * @text       text to draw
 * @highlight  whether text should be highlighted
 */
static void draw_cell_content(GxEPD2_GFX_BASE_CLASS &display, int16_t x0, int16_t y0, uint16_t w0, uint16_t h0, uint8_t xoff, uint8_t yoff, String &text, bool highlight = false) {
	int16_t x, y;
	uint16_t w, h;

	display.getTextBounds(text, 0, 0, &x, &y, &w, &h);

	int16_t w_diff = w0 - w;
	int x2 = x0 + xoff * w0 + w_diff/2 - x;
	int y2 = y0 + yoff * h0 - y;

	display.setCursor(x2, y2);
	display.print(text);
	if (highlight) {
		display.drawCircle(x2 + x + w/2, y2 - h/2, (w0 - CELL_SPACING) / 2, GxEPD_BLACK);
	}
}

void draw_calendar(GxEPD2_GFX_BASE_CLASS &display, int16_t x0, int16_t y0) {
	struct tm now;
	if (!getLocalTime(&now)) {
		return;
	}

	uint8_t n_days = days_in_month(now.tm_mon, now.tm_year);

	/* on which weekday is the 1st? */
	int8_t day_of_1st = ((1 - 7 - (now.tm_mday - now.tm_wday)) % 7) + 7;

	/* remap days from So-Sa = 0..6 to Mo-So = 0..6 */
	day_of_1st = (day_of_1st - 1 + 7) % 7;

	/* determine sizes */
	int16_t x, y;
	uint16_t w, h, cell_width, cell_height;
	display.getTextBounds(week_days[0], 0, 0, &x, &y, &w, &h);
	cell_width = w + CELL_SPACING;
	cell_height = h + CELL_SPACING;

	/* draw title with month and year */
	display.setFont(&FreeSansBold12pt7b);
	String title_text = String(months[now.tm_mon]) + " " + String(1900 + now.tm_year);
	draw_cell_content(display, x0, y0, cell_width * 7, h, 0, 0, title_text);
	y0 += h + 2 * CELL_SPACING;

	/* draw table header with week days */
	display.setFont(&FreeSansBold9pt7b);
	for (int i=0; i<7; i++) {
		String week_day = String(week_days[i]);
		draw_cell_content(display, x0, y0, cell_width, cell_height, i, 0, week_day);
	}

	/* draw days */
	display.setFont(&FreeSans9pt7b);
	int8_t wday = day_of_1st;
	uint8_t row = 1;
	for (uint8_t day = 1; day <= n_days; day++) {
		String day_str = String(day);
		draw_cell_content(display, x0, y0, cell_width, cell_height, wday, row, day_str, day == now.tm_mday);

		wday++;
		if (wday > 6) {
			wday = 0;
			row++;
		}
	}
}