diff options
Diffstat (limited to 'src/ui-calendar.c')
-rw-r--r-- | src/ui-calendar.c | 220 |
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); |