aboutsummaryrefslogtreecommitdiffstats
path: root/src/ui-calendar.c
diff options
context:
space:
mode:
authorLars Henriksen <LarsHenriksen@get2net.dk>2018-12-27 12:08:25 +0100
committerLukas Fleischer <lfleischer@calcurse.org>2019-05-22 01:56:59 -0400
commit0bb4a59b5fb089062f0eb369d39289ff1ccfc2ba (patch)
tree7186551e8e2be5ad5643c4e5d7e57ce98037e80b /src/ui-calendar.c
parent4284ca91bc0fd04851a34c67dae1068f3c1defc9 (diff)
downloadcalcurse-0bb4a59b5fb089062f0eb369d39289ff1ccfc2ba.tar.gz
calcurse-0bb4a59b5fb089062f0eb369d39289ff1ccfc2ba.zip
Add week numbers in the calendar and full first and last week
Much in the calendar is based on the selected day, struct date slctd_day, in ui-calendar.c. On the screen it is highlighted with a deviating colour. The highlight effect has been changed to a pair of red square brackets that do not obscure the day colour. The week number (in the frame) used to be that of the selected day, but has no obvious relation to the days in the APP panel. It has been replaced by the year day number of the selected day. The week numbers of all visible weeks are displayed to the left of the calendar. Dates are displayed also for the overlapping parts of the first and last week of the month (which do not belong to the month). Days are accessible in the appointments panel as well as in the calendar. Hence, validation of days (= inside UNIX time limits) must be extended from the calendar (in ui_calendar_move()) to include loaded days (in day_store_items()). Signed-off-by: Lars Henriksen <LarsHenriksen@get2net.dk> Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
Diffstat (limited to 'src/ui-calendar.c')
-rw-r--r--src/ui-calendar.c220
1 files changed, 134 insertions, 86 deletions
diff --git a/src/ui-calendar.c b/src/ui-calendar.c
index 5b8ab1f..e4e1b4d 100644
--- a/src/ui-calendar.c
+++ b/src/ui-calendar.c
@@ -54,7 +54,8 @@ static void (*draw_calendar[CAL_VIEWS]) (struct scrollwin *, struct date *,
unsigned) = {
draw_monthly_view, draw_weekly_view};
-static int monthly_view_cache[MAXDAYSPERMONTH];
+/* Six weeks cover a month. */
+static int monthly_view_cache[WEEKINDAYS * 6];
static int monthly_view_cache_valid = 0;
static int monthly_view_cache_month = 0;
@@ -207,29 +208,6 @@ static int ui_calendar_get_wday(struct date *date)
return t.tm_wday;
}
-static unsigned months_to_days(unsigned month)
-{
- return (month * 3057 - 3007) / 100;
-}
-
-static long years_to_days(unsigned year)
-{
- return year * 365L + year / 4 - year / 100 + year / 400;
-}
-
-static long ymd_to_scalar(unsigned year, unsigned month, unsigned day)
-{
- long scalar;
-
- scalar = day + months_to_days(month);
- if (month > 2)
- scalar -= ISLEAP(year) ? 1 : 2;
- year--;
- scalar += years_to_days(year);
-
- return scalar;
-}
-
void ui_calendar_monthly_view_cache_set_invalid(void)
{
monthly_view_cache_valid = 0;
@@ -308,6 +286,29 @@ static int ISO8601weeknum(const struct tm *t)
return wnum;
}
+/*
+ * Return the tm structure for the first day of the first week
+ * (containing a day) of the selected month.
+ */
+static struct tm get_first_day(unsigned sunday_first)
+{
+ struct tm t;
+ struct date d;
+
+ d = slctd_day;
+
+ /* get the first day of the month */
+ d.dd = 1;
+ t = date2tm(d, 0, 0);
+ mktime(&t);
+ /* get the first day of the week */
+ date_change(&t, 0,
+ -(sunday_first ?
+ t.tm_wday :
+ (t.tm_wday + WEEKINDAYS - 1) % WEEKINDAYS));
+ return t;
+}
+
static struct tm get_first_weekday(unsigned sunday_first)
{
int c_wday, days_to_remove;
@@ -342,112 +343,160 @@ static void
draw_monthly_view(struct scrollwin *sw, struct date *current_day,
unsigned sunday_first)
{
- struct date check_day;
- int c_day, c_day_1, day_1_sav, numdays, j;
+ struct date c_day;
+ int slctd, w_day, numdays, j, week = 0;
unsigned yr, mo;
- int w, ofs_x, ofs_y;
- int item_this_day = 0;
- struct tm t;
+ int w, monthw, weekw, dayw, ofs_x, ofs_y;
+ struct tm t, t_first;
char *cp;
+ char bo, bc;
+ unsigned attr, day_attr;
+ int first_day, last_day;
werase(sw->inner);
+ /*
+ * number of days to display
+ */
+ first_day = last_day = 0;
+ /* days in the selected month */
+ numdays = days[slctd_day.mm - 1];
+ if (2 == slctd_day.mm && ISLEAP(slctd_day.yyyy))
+ ++numdays;
+ /*
+ * Step forward by week until past the last day of the month.
+ * The first day of the first week may belong to the previous month.
+ */
+ t = t_first = get_first_day(sunday_first);
+ t.tm_mday += WEEKINDAYS;
+ mktime(&t);
+ last_day += WEEKINDAYS;
+ /* following weeks */
+ for (j = t.tm_mday; j <= numdays; j += WEEKINDAYS )
+ last_day += WEEKINDAYS;
+
mo = slctd_day.mm;
yr = slctd_day.yyyy;
+ /* a week column plus seven day columns */
+ weekw = 3;
+ dayw = 4;
+ monthw = weekw + 7 * dayw;
+
/* offset for centering calendar in window */
w = wins_sbar_width() - 2;
ofs_y = 0;
- ofs_x = (w - 27) / 2;
-
- /* checking the number of days in february */
- numdays = days[mo - 1];
- if (2 == mo && ISLEAP(yr))
- ++numdays;
+ ofs_x = (w - monthw) / 2;
- /*
- * the first calendar day will be monday or sunday, depending on
- * 'week_begins_on_monday' value
- */
- c_day_1 =
- (int)((ymd_to_scalar(yr, mo, 1 + sunday_first) -
- (long)1) % 7L);
+ /* invalidate cache if a new month is selected */
+ if (yr * YEARINMONTHS + mo != monthly_view_cache_month) {
+ monthly_view_cache_month = yr * YEARINMONTHS + mo;
+ monthly_view_cache_valid = 0;
+ }
- /* Print the week number, calculated from monday. */
- t = get_first_weekday(0);
- draw_week_number(sw, t);
+ WINS_CALENDAR_LOCK;
+ /* Print the day number. */
+ t = date2tm(slctd_day, 0, 0);
+ mktime(&t);
+ custom_apply_attr(sw->win, ATTR_HIGHEST);
+ mvwprintw(sw->win, conf.compact_panels ? 0 : 2,
+ ofs_x + monthw - 6,
+ "(#%3d)", t.tm_yday + 1);
+ custom_remove_attr(sw->win, ATTR_HIGHEST);
/* Write the current month and year on top of the calendar */
- WINS_CALENDAR_LOCK;
custom_apply_attr(sw->inner, ATTR_HIGHEST);
cp = nl_langinfo(MON_1 + mo - 1);
mvwprintw(sw->inner, ofs_y, (w - (strlen(cp) + 5)) / 2,
"%s %d", cp, slctd_day.yyyy);
custom_remove_attr(sw->inner, ATTR_HIGHEST);
+
++ofs_y;
- /* print the days, with regards to the first day of the week */
+ /* print the days with regard to the first day of the week */
custom_apply_attr(sw->inner, ATTR_HIGHEST);
for (j = 0; j < WEEKINDAYS; j++) {
- mvwaddstr(sw->inner, ofs_y, ofs_x + 4 * j,
+ mvwaddstr(sw->inner, ofs_y, ofs_x + weekw + 4 * j,
nl_langinfo(ABDAY_1 + (1 + j - sunday_first) % WEEKINDAYS));
}
custom_remove_attr(sw->inner, ATTR_HIGHEST);
WINS_CALENDAR_UNLOCK;
- day_1_sav = (c_day_1 + 1) * 3 + c_day_1 - 7;
+ ++ofs_y;
- /* invalidate cache if a new month is selected */
- if (yr * YEARINMONTHS + mo != monthly_view_cache_month) {
- monthly_view_cache_month = yr * YEARINMONTHS + mo;
- monthly_view_cache_valid = 0;
- }
+ /* print the dates */
+ for (j = first_day, t = t_first, w_day = 0;
+ j < last_day;
+ j++, date_change(&t, 0, 1), w_day++, w_day %= WEEKINDAYS) {
+
+ c_day.dd = t.tm_mday;
+ c_day.mm = t.tm_mon + 1;
+ c_day.yyyy = t.tm_year + 1900;
+ slctd = !date_cmp(&c_day, &slctd_day);
+
+ /* Next line, week over. */
+ if (!w_day && j != first_day) {
+ ofs_y++;
+ ofs_x = (w - monthw) / 2;
+ }
- for (c_day = 1; c_day <= numdays; ++c_day, ++c_day_1, c_day_1 %= 7) {
- unsigned attr;
+ /* Week number, beware of first and last week of the year. */
+ if (!w_day) {
+ if (j == first_day ||
+ (mo == 1 && j == WEEKINDAYS) ||
+ (mo == 12 && j >= 4 * WEEKINDAYS)) {
+ if (sunday_first)
+ date_change(&t, 0, 1);
+ week = ISO8601weeknum(&t);
+ if (sunday_first)
+ date_change(&t, 0, -1);
+ } else
+ week++;
+ }
- check_day.dd = c_day;
- check_day.mm = slctd_day.mm;
- check_day.yyyy = slctd_day.yyyy;
+ /* Brackets for the selected day. */
+ bo = slctd ? '[' : ' ';
+ bc = slctd ? ']' : ' ';
/* check if the day contains an event or an appointment */
if (monthly_view_cache_valid) {
- item_this_day = monthly_view_cache[c_day - 1];
+ day_attr = monthly_view_cache[j];
} else {
- item_this_day = monthly_view_cache[c_day - 1] =
- day_check_if_item(check_day);
- }
-
- /* Go to next line, the week is over. */
- if (!c_day_1 && 1 != c_day) {
- ofs_y++;
- ofs_x = (w - 27) / 2 - day_1_sav - 4 * c_day;
+ day_attr = monthly_view_cache[j] =
+ day_check_if_item(c_day);
}
- if (c_day == current_day->dd
- && current_day->mm == slctd_day.mm
- && current_day->yyyy == slctd_day.yyyy
- && current_day->dd != slctd_day.dd)
+ /* Set day colours. */
+ if (date_cmp(&c_day, current_day) == 0)
attr = ATTR_LOWEST;
- else if (c_day == slctd_day.dd)
- attr = ATTR_MIDDLE;
- else if (item_this_day == 1)
- attr = ATTR_LOW;
- else if (item_this_day == 2)
- attr = ATTR_TRUE;
else
- attr = 0;
+ attr = day_attr;
WINS_CALENDAR_LOCK;
+ /* Print week number. */
+ if (!w_day) {
+ custom_apply_attr(sw->inner, ATTR_HIGHEST);
+ mvwprintw(sw->inner, ofs_y, ofs_x, "%2d", week);
+ custom_remove_attr(sw->inner, ATTR_HIGHEST);
+ }
+ /* Print date with attributes.*/
if (attr)
custom_apply_attr(sw->inner, attr);
- mvwprintw(sw->inner, ofs_y + 1,
- ofs_x + day_1_sav + 4 * c_day + 1, "%2d", c_day);
+ mvwprintw(sw->inner, ofs_y, ofs_x + weekw + w_day * 4,
+ "%c%2d%c", bo, c_day.dd, bc);
if (attr)
custom_remove_attr(sw->inner, attr);
+ /* Colour the brackets. */
+ if (slctd) {
+ mvwchgat(sw->inner, ofs_y, ofs_x + weekw + w_day * 4,
+ 1, A_BOLD,
+ (colorize ? (COLR_RED | A_BOLD) : 0), NULL);
+ mvwchgat(sw->inner, ofs_y, ofs_x + weekw + 3 + w_day * 4,
+ 1, A_BOLD,
+ (colorize ? (COLR_RED | A_BOLD) : 0), NULL);
+ }
WINS_CALENDAR_UNLOCK;
}
-
monthly_view_cache_valid = 1;
}
@@ -704,10 +753,9 @@ void ui_calendar_move(enum move move, int count)
ret = 1;
/* NOTREACHED */
}
- if (ret == 1 || (YEAR1902_2037 && t.tm_year < 2)
- || (YEAR1902_2037 && t.tm_year > 137)) {
- char *out, *msg = _("The move failed (%d/%d/%d, ret=%d)."), ch;
- asprintf(&out, msg, t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, ret);
+ if (ret || !check_date(t.tm_year + 1900, t.tm_mon + 1, t.tm_mday)) {
+ char *out, *msg = _("The move failed (%d/%d/%d)."), ch;
+ asprintf(&out, msg, t.tm_mday, t.tm_mon + 1, t.tm_year + 1900);
do {
status_mesg(out, _("Press [ENTER] to continue"));
ch = keys_wgetch(win[KEY].p);