14c8945a0SNathan Whitehorn /*
2*a96ef450SBaptiste Daroussin * $Id: calendar.c,v 1.106 2020/11/23 09:03:49 tom Exp $
34c8945a0SNathan Whitehorn *
44c8945a0SNathan Whitehorn * calendar.c -- implements the calendar box
54c8945a0SNathan Whitehorn *
6*a96ef450SBaptiste Daroussin * Copyright 2001-2019,2020 Thomas E. Dickey
74c8945a0SNathan Whitehorn *
84c8945a0SNathan Whitehorn * This program is free software; you can redistribute it and/or modify
94c8945a0SNathan Whitehorn * it under the terms of the GNU Lesser General Public License, version 2.1
104c8945a0SNathan Whitehorn * as published by the Free Software Foundation.
114c8945a0SNathan Whitehorn *
124c8945a0SNathan Whitehorn * This program is distributed in the hope that it will be useful, but
134c8945a0SNathan Whitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of
144c8945a0SNathan Whitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
154c8945a0SNathan Whitehorn * Lesser General Public License for more details.
164c8945a0SNathan Whitehorn *
174c8945a0SNathan Whitehorn * You should have received a copy of the GNU Lesser General Public
184c8945a0SNathan Whitehorn * License along with this program; if not, write to
194c8945a0SNathan Whitehorn * Free Software Foundation, Inc.
204c8945a0SNathan Whitehorn * 51 Franklin St., Fifth Floor
214c8945a0SNathan Whitehorn * Boston, MA 02110, USA.
224c8945a0SNathan Whitehorn */
234c8945a0SNathan Whitehorn
24*a96ef450SBaptiste Daroussin #include <dlg_internals.h>
254c8945a0SNathan Whitehorn #include <dlg_keys.h>
264c8945a0SNathan Whitehorn
274c8945a0SNathan Whitehorn #include <time.h>
284c8945a0SNathan Whitehorn
29f4f33ea0SBaptiste Daroussin #ifdef HAVE_STDINT_H
30f4f33ea0SBaptiste Daroussin #include <stdint.h>
31f4f33ea0SBaptiste Daroussin #else
32f4f33ea0SBaptiste Daroussin #define intptr_t long
33f4f33ea0SBaptiste Daroussin #endif
34f4f33ea0SBaptiste Daroussin
354c8945a0SNathan Whitehorn #define ONE_DAY (60 * 60 * 24)
364c8945a0SNathan Whitehorn
374c8945a0SNathan Whitehorn #define MON_WIDE 4 /* width of a month-name */
384c8945a0SNathan Whitehorn #define DAY_HIGH 6 /* maximum lines in day-grid */
394c8945a0SNathan Whitehorn #define DAY_WIDE (8 * MON_WIDE) /* width of the day-grid */
404c8945a0SNathan Whitehorn #define HDR_HIGH 1 /* height of cells with month/year */
414c8945a0SNathan Whitehorn #define BTN_HIGH 1 /* height of button-row excluding margin */
424c8945a0SNathan Whitehorn
434c8945a0SNathan Whitehorn /* two more lines: titles for day-of-week and month/year boxes */
44f4f33ea0SBaptiste Daroussin #define MIN_HIGH (DAY_HIGH + 2 + HDR_HIGH + BTN_HIGH + (MAX_DAYS * MARGIN))
454c8945a0SNathan Whitehorn #define MIN_WIDE (DAY_WIDE + (4 * MARGIN))
464c8945a0SNathan Whitehorn
474c8945a0SNathan Whitehorn typedef enum {
484c8945a0SNathan Whitehorn sMONTH = -3
494c8945a0SNathan Whitehorn ,sYEAR = -2
504c8945a0SNathan Whitehorn ,sDAY = -1
514c8945a0SNathan Whitehorn } STATES;
524c8945a0SNathan Whitehorn
534c8945a0SNathan Whitehorn struct _box;
544c8945a0SNathan Whitehorn
554c8945a0SNathan Whitehorn typedef int (*BOX_DRAW) (struct _box *, struct tm *);
564c8945a0SNathan Whitehorn
574c8945a0SNathan Whitehorn typedef struct _box {
584c8945a0SNathan Whitehorn WINDOW *parent;
594c8945a0SNathan Whitehorn WINDOW *window;
604c8945a0SNathan Whitehorn int x;
614c8945a0SNathan Whitehorn int y;
624c8945a0SNathan Whitehorn int width;
634c8945a0SNathan Whitehorn int height;
644c8945a0SNathan Whitehorn BOX_DRAW box_draw;
65f4f33ea0SBaptiste Daroussin int week_start;
664c8945a0SNathan Whitehorn } BOX;
674c8945a0SNathan Whitehorn
68f4f33ea0SBaptiste Daroussin #define MAX_DAYS 7
69f4f33ea0SBaptiste Daroussin #define MAX_MONTHS 12
70f4f33ea0SBaptiste Daroussin
71f4f33ea0SBaptiste Daroussin static char *cached_days[MAX_DAYS];
72f4f33ea0SBaptiste Daroussin static char *cached_months[MAX_MONTHS];
73f4f33ea0SBaptiste Daroussin
744c8945a0SNathan Whitehorn static const char *
nameOfDayOfWeek(int n)754c8945a0SNathan Whitehorn nameOfDayOfWeek(int n)
764c8945a0SNathan Whitehorn {
77f4f33ea0SBaptiste Daroussin static bool shown[MAX_DAYS];
784c8945a0SNathan Whitehorn
79f4f33ea0SBaptiste Daroussin while (n < 0) {
80f4f33ea0SBaptiste Daroussin n += MAX_DAYS;
81f4f33ea0SBaptiste Daroussin }
82f4f33ea0SBaptiste Daroussin n %= MAX_DAYS;
834c8945a0SNathan Whitehorn #ifdef ENABLE_NLS
84f4f33ea0SBaptiste Daroussin if (cached_days[n] == 0) {
85f4f33ea0SBaptiste Daroussin const nl_item items[MAX_DAYS] =
864c8945a0SNathan Whitehorn {
874c8945a0SNathan Whitehorn ABDAY_1, ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7
884c8945a0SNathan Whitehorn };
89f4f33ea0SBaptiste Daroussin cached_days[n] = dlg_strclone(nl_langinfo(items[n]));
90f4f33ea0SBaptiste Daroussin memset(shown, 0, sizeof(shown));
914c8945a0SNathan Whitehorn }
924c8945a0SNathan Whitehorn #endif
93f4f33ea0SBaptiste Daroussin if (cached_days[n] == 0) {
94*a96ef450SBaptiste Daroussin static const char *posix_days[MAX_DAYS] =
95*a96ef450SBaptiste Daroussin {
96*a96ef450SBaptiste Daroussin "Sunday",
97*a96ef450SBaptiste Daroussin "Monday",
98*a96ef450SBaptiste Daroussin "Tuesday",
99*a96ef450SBaptiste Daroussin "Wednesday",
100*a96ef450SBaptiste Daroussin "Thursday",
101*a96ef450SBaptiste Daroussin "Friday",
102*a96ef450SBaptiste Daroussin "Saturday"
103*a96ef450SBaptiste Daroussin };
104*a96ef450SBaptiste Daroussin size_t limit = MON_WIDE - 1;
105f4f33ea0SBaptiste Daroussin char *value = dlg_strclone(posix_days[n]);
106f4f33ea0SBaptiste Daroussin
107f4f33ea0SBaptiste Daroussin /*
108f4f33ea0SBaptiste Daroussin * POSIX does not actually say what the length of an abbreviated name
109f4f33ea0SBaptiste Daroussin * is. Typically it is 2, which will fit into our layout. That also
110f4f33ea0SBaptiste Daroussin * happens to work with CJK entries as seen in glibc, which are a
111f4f33ea0SBaptiste Daroussin * double-width cell. For now (2016/01/26), handle too-long names only
112f4f33ea0SBaptiste Daroussin * for POSIX values.
113f4f33ea0SBaptiste Daroussin */
114*a96ef450SBaptiste Daroussin if (strlen(value) > limit)
115f4f33ea0SBaptiste Daroussin value[limit] = '\0';
116f4f33ea0SBaptiste Daroussin cached_days[n] = value;
1174c8945a0SNathan Whitehorn }
118f4f33ea0SBaptiste Daroussin if (!shown[n]) {
119f4f33ea0SBaptiste Daroussin DLG_TRACE(("# DAY(%d) = '%s'\n", n, cached_days[n]));
120f4f33ea0SBaptiste Daroussin shown[n] = TRUE;
1214c8945a0SNathan Whitehorn }
122f4f33ea0SBaptiste Daroussin return cached_days[n];
1234c8945a0SNathan Whitehorn }
1244c8945a0SNathan Whitehorn
1254c8945a0SNathan Whitehorn static const char *
nameOfMonth(int n)1264c8945a0SNathan Whitehorn nameOfMonth(int n)
1274c8945a0SNathan Whitehorn {
128f4f33ea0SBaptiste Daroussin static bool shown[MAX_MONTHS];
1294c8945a0SNathan Whitehorn
130f4f33ea0SBaptiste Daroussin while (n < 0) {
131f4f33ea0SBaptiste Daroussin n += MAX_MONTHS;
132f4f33ea0SBaptiste Daroussin }
133f4f33ea0SBaptiste Daroussin n %= MAX_MONTHS;
1344c8945a0SNathan Whitehorn #ifdef ENABLE_NLS
135f4f33ea0SBaptiste Daroussin if (cached_months[n] == 0) {
136f4f33ea0SBaptiste Daroussin const nl_item items[MAX_MONTHS] =
1374c8945a0SNathan Whitehorn {
1384c8945a0SNathan Whitehorn MON_1, MON_2, MON_3, MON_4, MON_5, MON_6,
1394c8945a0SNathan Whitehorn MON_7, MON_8, MON_9, MON_10, MON_11, MON_12
1404c8945a0SNathan Whitehorn };
141f4f33ea0SBaptiste Daroussin cached_months[n] = dlg_strclone(nl_langinfo(items[n]));
142f4f33ea0SBaptiste Daroussin memset(shown, 0, sizeof(shown));
1434c8945a0SNathan Whitehorn }
1444c8945a0SNathan Whitehorn #endif
145f4f33ea0SBaptiste Daroussin if (cached_months[n] == 0) {
146*a96ef450SBaptiste Daroussin static const char *posix_mons[MAX_MONTHS] =
147*a96ef450SBaptiste Daroussin {
148*a96ef450SBaptiste Daroussin "January",
149*a96ef450SBaptiste Daroussin "February",
150*a96ef450SBaptiste Daroussin "March",
151*a96ef450SBaptiste Daroussin "April",
152*a96ef450SBaptiste Daroussin "May",
153*a96ef450SBaptiste Daroussin "June",
154*a96ef450SBaptiste Daroussin "July",
155*a96ef450SBaptiste Daroussin "August",
156*a96ef450SBaptiste Daroussin "September",
157*a96ef450SBaptiste Daroussin "October",
158*a96ef450SBaptiste Daroussin "November",
159*a96ef450SBaptiste Daroussin "December"
160*a96ef450SBaptiste Daroussin };
161f4f33ea0SBaptiste Daroussin cached_months[n] = dlg_strclone(posix_mons[n]);
1624c8945a0SNathan Whitehorn }
163f4f33ea0SBaptiste Daroussin if (!shown[n]) {
164f4f33ea0SBaptiste Daroussin DLG_TRACE(("# MON(%d) = '%s'\n", n, cached_months[n]));
165f4f33ea0SBaptiste Daroussin shown[n] = TRUE;
1664c8945a0SNathan Whitehorn }
167f4f33ea0SBaptiste Daroussin return cached_months[n];
168f4f33ea0SBaptiste Daroussin }
169f4f33ea0SBaptiste Daroussin
170f4f33ea0SBaptiste Daroussin /*
171f4f33ea0SBaptiste Daroussin * Algorithm for Gregorian calendar.
172f4f33ea0SBaptiste Daroussin */
173f4f33ea0SBaptiste Daroussin static int
isleap(int y)174f4f33ea0SBaptiste Daroussin isleap(int y)
175f4f33ea0SBaptiste Daroussin {
176f4f33ea0SBaptiste Daroussin return ((y % 4 == 0) &&
177f4f33ea0SBaptiste Daroussin ((y % 100 != 0) ||
178f4f33ea0SBaptiste Daroussin (y % 400 == 0))) ? 1 : 0;
179f4f33ea0SBaptiste Daroussin }
180f4f33ea0SBaptiste Daroussin
181f4f33ea0SBaptiste Daroussin static void
adjust_year_month(int * year,int * month)182f4f33ea0SBaptiste Daroussin adjust_year_month(int *year, int *month)
183f4f33ea0SBaptiste Daroussin {
184f4f33ea0SBaptiste Daroussin while (*month < 0) {
185f4f33ea0SBaptiste Daroussin *month += MAX_MONTHS;
186f4f33ea0SBaptiste Daroussin *year -= 1;
187f4f33ea0SBaptiste Daroussin }
188f4f33ea0SBaptiste Daroussin while (*month >= MAX_MONTHS) {
189f4f33ea0SBaptiste Daroussin *month -= MAX_MONTHS;
190f4f33ea0SBaptiste Daroussin *year += 1;
191f4f33ea0SBaptiste Daroussin }
1924c8945a0SNathan Whitehorn }
1934c8945a0SNathan Whitehorn
1944c8945a0SNathan Whitehorn static int
days_per_month(int year,int month)195f4f33ea0SBaptiste Daroussin days_per_month(int year, int month)
1964c8945a0SNathan Whitehorn {
1974c8945a0SNathan Whitehorn static const int nominal[] =
1984c8945a0SNathan Whitehorn {
1994c8945a0SNathan Whitehorn 31, 28, 31, 30, 31, 30,
2004c8945a0SNathan Whitehorn 31, 31, 30, 31, 30, 31
2014c8945a0SNathan Whitehorn };
2024c8945a0SNathan Whitehorn int result;
2034c8945a0SNathan Whitehorn
204f4f33ea0SBaptiste Daroussin adjust_year_month(&year, &month);
2054c8945a0SNathan Whitehorn result = nominal[month];
2064c8945a0SNathan Whitehorn if (month == 1)
207f4f33ea0SBaptiste Daroussin result += isleap(year);
2084c8945a0SNathan Whitehorn return result;
2094c8945a0SNathan Whitehorn }
2104c8945a0SNathan Whitehorn
2114c8945a0SNathan Whitehorn static int
days_in_month(struct tm * current,int offset)212f4f33ea0SBaptiste Daroussin days_in_month(struct tm *current, int offset /* -1, 0, 1 */ )
213f4f33ea0SBaptiste Daroussin {
214f4f33ea0SBaptiste Daroussin int year = current->tm_year + 1900;
215f4f33ea0SBaptiste Daroussin int month = current->tm_mon + offset;
216f4f33ea0SBaptiste Daroussin
217f4f33ea0SBaptiste Daroussin adjust_year_month(&year, &month);
218f4f33ea0SBaptiste Daroussin return days_per_month(year, month);
219f4f33ea0SBaptiste Daroussin }
220f4f33ea0SBaptiste Daroussin
221f4f33ea0SBaptiste Daroussin static int
days_per_year(int year)222f4f33ea0SBaptiste Daroussin days_per_year(int year)
223f4f33ea0SBaptiste Daroussin {
224f4f33ea0SBaptiste Daroussin return (isleap(year) ? 366 : 365);
225f4f33ea0SBaptiste Daroussin }
226f4f33ea0SBaptiste Daroussin
227f4f33ea0SBaptiste Daroussin static int
days_in_year(struct tm * current,int offset)2284c8945a0SNathan Whitehorn days_in_year(struct tm *current, int offset /* -1, 0, 1 */ )
2294c8945a0SNathan Whitehorn {
230f4f33ea0SBaptiste Daroussin return days_per_year(current->tm_year + 1900 + offset);
231f4f33ea0SBaptiste Daroussin }
2324c8945a0SNathan Whitehorn
233f4f33ea0SBaptiste Daroussin /*
234f4f33ea0SBaptiste Daroussin * Adapted from C FAQ
235f4f33ea0SBaptiste Daroussin * "17.28: How can I find the day of the week given the date?"
236f4f33ea0SBaptiste Daroussin * implementation by Tomohiko Sakamoto.
237f4f33ea0SBaptiste Daroussin *
238f4f33ea0SBaptiste Daroussin * d = day (0 to whatever)
239f4f33ea0SBaptiste Daroussin * m = month (1 through 12)
240f4f33ea0SBaptiste Daroussin * y = year (1752 and later, for Gregorian calendar)
241f4f33ea0SBaptiste Daroussin */
242f4f33ea0SBaptiste Daroussin static int
day_of_week(int y,int m,int d)243f4f33ea0SBaptiste Daroussin day_of_week(int y, int m, int d)
244f4f33ea0SBaptiste Daroussin {
245f4f33ea0SBaptiste Daroussin static int t[] =
246f4f33ea0SBaptiste Daroussin {
247f4f33ea0SBaptiste Daroussin 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4
248f4f33ea0SBaptiste Daroussin };
249f4f33ea0SBaptiste Daroussin y -= (m < 3);
250f4f33ea0SBaptiste Daroussin return (6 + (y + (y / 4) - (y / 100) + (y / 400) + t[m - 1] + d)) % MAX_DAYS;
251f4f33ea0SBaptiste Daroussin }
252f4f33ea0SBaptiste Daroussin
253f4f33ea0SBaptiste Daroussin static int
day_in_year(int year,int month,int day)254f4f33ea0SBaptiste Daroussin day_in_year(int year, int month, int day)
255f4f33ea0SBaptiste Daroussin {
256f4f33ea0SBaptiste Daroussin int result = day;
257f4f33ea0SBaptiste Daroussin while (--month >= 1)
258f4f33ea0SBaptiste Daroussin result += days_per_month(year, month);
259f4f33ea0SBaptiste Daroussin return result;
260f4f33ea0SBaptiste Daroussin }
261f4f33ea0SBaptiste Daroussin
262f4f33ea0SBaptiste Daroussin static int
iso_week(int year,int month,int day)263f4f33ea0SBaptiste Daroussin iso_week(int year, int month, int day)
264f4f33ea0SBaptiste Daroussin {
265f4f33ea0SBaptiste Daroussin int week = 1;
266f4f33ea0SBaptiste Daroussin int dow;
267f4f33ea0SBaptiste Daroussin int new_year_dow;
268f4f33ea0SBaptiste Daroussin int diy;
269f4f33ea0SBaptiste Daroussin int new_years_eve_dow;
270f4f33ea0SBaptiste Daroussin static const int thursday = 3;
271f4f33ea0SBaptiste Daroussin
272f4f33ea0SBaptiste Daroussin /* add the number weeks *between* date and newyear */
273f4f33ea0SBaptiste Daroussin diy = day_in_year(year, month, day);
274f4f33ea0SBaptiste Daroussin week += (diy - 1) / MAX_DAYS;
275f4f33ea0SBaptiste Daroussin
276f4f33ea0SBaptiste Daroussin /* 0 = Monday */
277f4f33ea0SBaptiste Daroussin dow = day_of_week(year, month, day);
278f4f33ea0SBaptiste Daroussin new_year_dow = day_of_week(year, 1, 1);
279f4f33ea0SBaptiste Daroussin
280f4f33ea0SBaptiste Daroussin /*
281f4f33ea0SBaptiste Daroussin * If New Year falls on Friday, Saturday or Sunday, then New Years's week
282f4f33ea0SBaptiste Daroussin * is the last week of the preceding year. In that case subtract one week.
283f4f33ea0SBaptiste Daroussin */
284f4f33ea0SBaptiste Daroussin if (new_year_dow > thursday)
285f4f33ea0SBaptiste Daroussin --week;
286f4f33ea0SBaptiste Daroussin
287f4f33ea0SBaptiste Daroussin /* Add one week if there is a Sunday to Monday transition. */
288f4f33ea0SBaptiste Daroussin if (dow - new_year_dow < 0)
289f4f33ea0SBaptiste Daroussin ++week;
290f4f33ea0SBaptiste Daroussin
291f4f33ea0SBaptiste Daroussin /* Check if we are in the last week of the preceding year. */
292f4f33ea0SBaptiste Daroussin if (week < 1) {
293f4f33ea0SBaptiste Daroussin week = iso_week(--year, 12, 31);
294f4f33ea0SBaptiste Daroussin }
295f4f33ea0SBaptiste Daroussin
296f4f33ea0SBaptiste Daroussin /*
297f4f33ea0SBaptiste Daroussin * If we are in the same week as New Year's eve, check if New Year's eve is
298f4f33ea0SBaptiste Daroussin * in the first week of the next year.
299f4f33ea0SBaptiste Daroussin */
300f4f33ea0SBaptiste Daroussin new_years_eve_dow = (new_year_dow + 364 + isleap(year)) % MAX_DAYS;
301f4f33ea0SBaptiste Daroussin if (365 + isleap(year) - diy < MAX_DAYS
302f4f33ea0SBaptiste Daroussin && new_years_eve_dow >= dow
303f4f33ea0SBaptiste Daroussin && new_years_eve_dow < thursday) {
304f4f33ea0SBaptiste Daroussin week = 1;
305f4f33ea0SBaptiste Daroussin }
306f4f33ea0SBaptiste Daroussin return week;
307f4f33ea0SBaptiste Daroussin }
308f4f33ea0SBaptiste Daroussin
309f4f33ea0SBaptiste Daroussin static int *
getisoweeks(int year,int month)310f4f33ea0SBaptiste Daroussin getisoweeks(int year, int month)
311f4f33ea0SBaptiste Daroussin {
312f4f33ea0SBaptiste Daroussin static int result[10];
313f4f33ea0SBaptiste Daroussin int windx = 0;
314f4f33ea0SBaptiste Daroussin int day;
315f4f33ea0SBaptiste Daroussin int dpm = days_per_month(year, month);
316f4f33ea0SBaptiste Daroussin
317f4f33ea0SBaptiste Daroussin for (day = 1; day <= dpm; day += MAX_DAYS)
318f4f33ea0SBaptiste Daroussin result[windx++] = iso_week(year, month, day);
319f4f33ea0SBaptiste Daroussin /*
320f4f33ea0SBaptiste Daroussin * Ensure that there is a week number associated with the last day of the
321f4f33ea0SBaptiste Daroussin * month, e.g., in case the last day of the month falls before Thursday,
322f4f33ea0SBaptiste Daroussin * so that we have to show the week-number for the beginning of the
323f4f33ea0SBaptiste Daroussin * following month.
324f4f33ea0SBaptiste Daroussin */
325f4f33ea0SBaptiste Daroussin result[windx] = iso_week(year, month, dpm);
326f4f33ea0SBaptiste Daroussin return result;
3274c8945a0SNathan Whitehorn }
3284c8945a0SNathan Whitehorn
3294c8945a0SNathan Whitehorn static int
day_cell_number(struct tm * current)3304c8945a0SNathan Whitehorn day_cell_number(struct tm *current)
3314c8945a0SNathan Whitehorn {
3324c8945a0SNathan Whitehorn int cell;
333f4f33ea0SBaptiste Daroussin cell = current->tm_mday - ((6 + current->tm_mday - current->tm_wday) % MAX_DAYS);
334f4f33ea0SBaptiste Daroussin if ((current->tm_mday - 1) % MAX_DAYS != current->tm_wday)
3354c8945a0SNathan Whitehorn cell += 6;
3364c8945a0SNathan Whitehorn else
3374c8945a0SNathan Whitehorn cell--;
3384c8945a0SNathan Whitehorn return cell;
3394c8945a0SNathan Whitehorn }
3404c8945a0SNathan Whitehorn
3414c8945a0SNathan Whitehorn static int
next_or_previous(int key,int two_d)3424c8945a0SNathan Whitehorn next_or_previous(int key, int two_d)
3434c8945a0SNathan Whitehorn {
3444c8945a0SNathan Whitehorn int result = 0;
3454c8945a0SNathan Whitehorn
3464c8945a0SNathan Whitehorn switch (key) {
3474c8945a0SNathan Whitehorn case DLGK_GRID_UP:
348f4f33ea0SBaptiste Daroussin result = two_d ? -MAX_DAYS : -1;
3494c8945a0SNathan Whitehorn break;
3504c8945a0SNathan Whitehorn case DLGK_GRID_LEFT:
3514c8945a0SNathan Whitehorn result = -1;
3524c8945a0SNathan Whitehorn break;
3534c8945a0SNathan Whitehorn case DLGK_GRID_DOWN:
354f4f33ea0SBaptiste Daroussin result = two_d ? MAX_DAYS : 1;
3554c8945a0SNathan Whitehorn break;
3564c8945a0SNathan Whitehorn case DLGK_GRID_RIGHT:
3574c8945a0SNathan Whitehorn result = 1;
3584c8945a0SNathan Whitehorn break;
3594c8945a0SNathan Whitehorn default:
3604c8945a0SNathan Whitehorn beep();
3614c8945a0SNathan Whitehorn break;
3624c8945a0SNathan Whitehorn }
3634c8945a0SNathan Whitehorn return result;
3644c8945a0SNathan Whitehorn }
3654c8945a0SNathan Whitehorn
3664c8945a0SNathan Whitehorn /*
3674c8945a0SNathan Whitehorn * Draw the day-of-month selection box
3684c8945a0SNathan Whitehorn */
3694c8945a0SNathan Whitehorn static int
draw_day(BOX * data,struct tm * current)3704c8945a0SNathan Whitehorn draw_day(BOX * data, struct tm *current)
3714c8945a0SNathan Whitehorn {
3724c8945a0SNathan Whitehorn int cell_wide = MON_WIDE;
373*a96ef450SBaptiste Daroussin int y, x, this_x;
3744c8945a0SNathan Whitehorn int save_y = 0, save_x = 0;
3754c8945a0SNathan Whitehorn int day = current->tm_mday;
3764c8945a0SNathan Whitehorn int mday;
377f4f33ea0SBaptiste Daroussin int week = 0;
378f4f33ea0SBaptiste Daroussin int windx = 0;
379f4f33ea0SBaptiste Daroussin int *weeks = 0;
3804c8945a0SNathan Whitehorn int last = days_in_month(current, 0);
3814c8945a0SNathan Whitehorn int prev = days_in_month(current, -1);
3824c8945a0SNathan Whitehorn
3834c8945a0SNathan Whitehorn werase(data->window);
3842a3e3873SBaptiste Daroussin dlg_draw_box2(data->parent,
3854c8945a0SNathan Whitehorn data->y - MARGIN, data->x - MARGIN,
3864c8945a0SNathan Whitehorn data->height + (2 * MARGIN), data->width + (2 * MARGIN),
3872a3e3873SBaptiste Daroussin menubox_attr,
3882a3e3873SBaptiste Daroussin menubox_border_attr,
3892a3e3873SBaptiste Daroussin menubox_border2_attr);
3904c8945a0SNathan Whitehorn
391f4f33ea0SBaptiste Daroussin dlg_attrset(data->window, menubox_attr); /* daynames headline */
392f4f33ea0SBaptiste Daroussin for (x = 0; x < MAX_DAYS; x++) {
3934c8945a0SNathan Whitehorn mvwprintw(data->window,
3944c8945a0SNathan Whitehorn 0, (x + 1) * cell_wide, "%*.*s ",
3954c8945a0SNathan Whitehorn cell_wide - 1,
3964c8945a0SNathan Whitehorn cell_wide - 1,
397f4f33ea0SBaptiste Daroussin nameOfDayOfWeek(x + data->week_start));
3984c8945a0SNathan Whitehorn }
3994c8945a0SNathan Whitehorn
400f4f33ea0SBaptiste Daroussin mday = ((6 + current->tm_mday -
401f4f33ea0SBaptiste Daroussin current->tm_wday +
402f4f33ea0SBaptiste Daroussin data->week_start) % MAX_DAYS) - MAX_DAYS;
403f4f33ea0SBaptiste Daroussin if (mday <= -MAX_DAYS)
404f4f33ea0SBaptiste Daroussin mday += MAX_DAYS;
405f4f33ea0SBaptiste Daroussin
406f4f33ea0SBaptiste Daroussin if (dialog_vars.iso_week) {
407f4f33ea0SBaptiste Daroussin weeks = getisoweeks(current->tm_year + 1900, current->tm_mon + 1);
408f4f33ea0SBaptiste Daroussin } else {
4094c8945a0SNathan Whitehorn /* mday is now in the range -6 to 0. */
410f4f33ea0SBaptiste Daroussin week = (current->tm_yday + 6 + mday - current->tm_mday) / MAX_DAYS;
411f4f33ea0SBaptiste Daroussin }
4124c8945a0SNathan Whitehorn
4134c8945a0SNathan Whitehorn for (y = 1; mday < last; y++) {
414f4f33ea0SBaptiste Daroussin dlg_attrset(data->window, menubox_attr); /* weeknumbers headline */
4154c8945a0SNathan Whitehorn mvwprintw(data->window,
4164c8945a0SNathan Whitehorn y, 0,
4174c8945a0SNathan Whitehorn "%*d ",
4184c8945a0SNathan Whitehorn cell_wide - 1,
419f4f33ea0SBaptiste Daroussin weeks ? weeks[windx++] : ++week);
420f4f33ea0SBaptiste Daroussin for (x = 0; x < MAX_DAYS; x++) {
4214c8945a0SNathan Whitehorn this_x = 1 + (x + 1) * cell_wide;
4224c8945a0SNathan Whitehorn ++mday;
4234c8945a0SNathan Whitehorn if (wmove(data->window, y, this_x) == ERR)
4244c8945a0SNathan Whitehorn continue;
425f4f33ea0SBaptiste Daroussin dlg_attrset(data->window, item_attr); /* not selected days */
4264c8945a0SNathan Whitehorn if (mday == day) {
427f4f33ea0SBaptiste Daroussin dlg_attrset(data->window, item_selected_attr); /* selected day */
4284c8945a0SNathan Whitehorn save_y = y;
4294c8945a0SNathan Whitehorn save_x = this_x;
4304c8945a0SNathan Whitehorn }
4314c8945a0SNathan Whitehorn if (mday > 0) {
4324c8945a0SNathan Whitehorn if (mday <= last) {
4334c8945a0SNathan Whitehorn wprintw(data->window, "%*d", cell_wide - 2, mday);
4344c8945a0SNathan Whitehorn } else if (mday == day) {
4354c8945a0SNathan Whitehorn wprintw(data->window, "%*d", cell_wide - 2, mday - last);
4364c8945a0SNathan Whitehorn }
4374c8945a0SNathan Whitehorn } else if (mday == day) {
4384c8945a0SNathan Whitehorn wprintw(data->window, "%*d", cell_wide - 2, mday + prev);
4394c8945a0SNathan Whitehorn }
4404c8945a0SNathan Whitehorn }
4414c8945a0SNathan Whitehorn wmove(data->window, save_y, save_x);
4424c8945a0SNathan Whitehorn }
4434c8945a0SNathan Whitehorn /* just draw arrows - scrollbar is unsuitable here */
4444c8945a0SNathan Whitehorn dlg_draw_arrows(data->parent, TRUE, TRUE,
4454c8945a0SNathan Whitehorn data->x + ARROWS_COL,
4464c8945a0SNathan Whitehorn data->y - 1,
4474c8945a0SNathan Whitehorn data->y + data->height);
4484c8945a0SNathan Whitehorn
4494c8945a0SNathan Whitehorn return 0;
4504c8945a0SNathan Whitehorn }
4514c8945a0SNathan Whitehorn
4524c8945a0SNathan Whitehorn /*
4534c8945a0SNathan Whitehorn * Draw the month-of-year selection box
4544c8945a0SNathan Whitehorn */
4554c8945a0SNathan Whitehorn static int
draw_month(BOX * data,struct tm * current)4564c8945a0SNathan Whitehorn draw_month(BOX * data, struct tm *current)
4574c8945a0SNathan Whitehorn {
4584c8945a0SNathan Whitehorn int month;
4594c8945a0SNathan Whitehorn
4604c8945a0SNathan Whitehorn month = current->tm_mon + 1;
4614c8945a0SNathan Whitehorn
462f4f33ea0SBaptiste Daroussin dlg_attrset(data->parent, dialog_attr); /* Headline "Month" */
4634c8945a0SNathan Whitehorn (void) mvwprintw(data->parent, data->y - 2, data->x - 1, _("Month"));
4642a3e3873SBaptiste Daroussin dlg_draw_box2(data->parent,
4654c8945a0SNathan Whitehorn data->y - 1, data->x - 1,
4664c8945a0SNathan Whitehorn data->height + 2, data->width + 2,
4672a3e3873SBaptiste Daroussin menubox_attr,
4682a3e3873SBaptiste Daroussin menubox_border_attr,
4692a3e3873SBaptiste Daroussin menubox_border2_attr);
470f4f33ea0SBaptiste Daroussin dlg_attrset(data->window, item_attr); /* color the month selection */
4714c8945a0SNathan Whitehorn mvwprintw(data->window, 0, 0, "%s", nameOfMonth(month - 1));
4724c8945a0SNathan Whitehorn wmove(data->window, 0, 0);
4734c8945a0SNathan Whitehorn return 0;
4744c8945a0SNathan Whitehorn }
4754c8945a0SNathan Whitehorn
4764c8945a0SNathan Whitehorn /*
4774c8945a0SNathan Whitehorn * Draw the year selection box
4784c8945a0SNathan Whitehorn */
4794c8945a0SNathan Whitehorn static int
draw_year(BOX * data,struct tm * current)4804c8945a0SNathan Whitehorn draw_year(BOX * data, struct tm *current)
4814c8945a0SNathan Whitehorn {
4824c8945a0SNathan Whitehorn int year = current->tm_year + 1900;
4834c8945a0SNathan Whitehorn
484f4f33ea0SBaptiste Daroussin dlg_attrset(data->parent, dialog_attr); /* Headline "Year" */
4854c8945a0SNathan Whitehorn (void) mvwprintw(data->parent, data->y - 2, data->x - 1, _("Year"));
4862a3e3873SBaptiste Daroussin dlg_draw_box2(data->parent,
4874c8945a0SNathan Whitehorn data->y - 1, data->x - 1,
4884c8945a0SNathan Whitehorn data->height + 2, data->width + 2,
4892a3e3873SBaptiste Daroussin menubox_attr,
4902a3e3873SBaptiste Daroussin menubox_border_attr,
4912a3e3873SBaptiste Daroussin menubox_border2_attr);
492f4f33ea0SBaptiste Daroussin dlg_attrset(data->window, item_attr); /* color the year selection */
4934c8945a0SNathan Whitehorn mvwprintw(data->window, 0, 0, "%4d", year);
4944c8945a0SNathan Whitehorn wmove(data->window, 0, 0);
4954c8945a0SNathan Whitehorn return 0;
4964c8945a0SNathan Whitehorn }
4974c8945a0SNathan Whitehorn
4984c8945a0SNathan Whitehorn static int
init_object(BOX * data,WINDOW * parent,int x,int y,int width,int height,BOX_DRAW box_draw,int key_offset,int code)4994c8945a0SNathan Whitehorn init_object(BOX * data,
5004c8945a0SNathan Whitehorn WINDOW *parent,
5014c8945a0SNathan Whitehorn int x, int y,
5024c8945a0SNathan Whitehorn int width, int height,
5034c8945a0SNathan Whitehorn BOX_DRAW box_draw,
504f4f33ea0SBaptiste Daroussin int key_offset,
5054c8945a0SNathan Whitehorn int code)
5064c8945a0SNathan Whitehorn {
5074c8945a0SNathan Whitehorn data->parent = parent;
5084c8945a0SNathan Whitehorn data->x = x;
5094c8945a0SNathan Whitehorn data->y = y;
5104c8945a0SNathan Whitehorn data->width = width;
5114c8945a0SNathan Whitehorn data->height = height;
5124c8945a0SNathan Whitehorn data->box_draw = box_draw;
513f4f33ea0SBaptiste Daroussin data->week_start = key_offset;
5144c8945a0SNathan Whitehorn
515*a96ef450SBaptiste Daroussin data->window = dlg_der_window(data->parent,
5164c8945a0SNathan Whitehorn data->height, data->width,
5174c8945a0SNathan Whitehorn data->y, data->x);
5184c8945a0SNathan Whitehorn if (data->window == 0)
5194c8945a0SNathan Whitehorn return -1;
5204c8945a0SNathan Whitehorn
5214c8945a0SNathan Whitehorn dlg_mouse_setbase(getbegx(parent), getbegy(parent));
5224c8945a0SNathan Whitehorn if (code == 'D') {
5234c8945a0SNathan Whitehorn dlg_mouse_mkbigregion(y + 1, x + MON_WIDE, height - 1, width - MON_WIDE,
524f4f33ea0SBaptiste Daroussin KEY_MAX + key_offset, 1, MON_WIDE, 3);
5254c8945a0SNathan Whitehorn } else {
5264c8945a0SNathan Whitehorn dlg_mouse_mkregion(y, x, height, width, code);
5274c8945a0SNathan Whitehorn }
5284c8945a0SNathan Whitehorn
5294c8945a0SNathan Whitehorn return 0;
5304c8945a0SNathan Whitehorn }
5314c8945a0SNathan Whitehorn
532f4f33ea0SBaptiste Daroussin #if defined(ENABLE_NLS) && defined(HAVE_NL_LANGINFO_1STDAY)
533f4f33ea0SBaptiste Daroussin #elif defined(HAVE_DLG_GAUGE)
534f4f33ea0SBaptiste Daroussin static int
read_locale_setting(const char * name,int which)535f4f33ea0SBaptiste Daroussin read_locale_setting(const char *name, int which)
536f4f33ea0SBaptiste Daroussin {
537f4f33ea0SBaptiste Daroussin FILE *fp;
538f4f33ea0SBaptiste Daroussin char command[80];
539f4f33ea0SBaptiste Daroussin int result = -1;
540f4f33ea0SBaptiste Daroussin
541f4f33ea0SBaptiste Daroussin sprintf(command, "locale %s", name);
542f4f33ea0SBaptiste Daroussin if ((fp = dlg_popen(command, "r")) != 0) {
543f4f33ea0SBaptiste Daroussin int count = 0;
544f4f33ea0SBaptiste Daroussin char buf[80];
545f4f33ea0SBaptiste Daroussin
546f4f33ea0SBaptiste Daroussin while (fgets(buf, (int) sizeof(buf) - 1, fp) != 0) {
547f4f33ea0SBaptiste Daroussin if (++count > which) {
548f4f33ea0SBaptiste Daroussin char *next = 0;
549f4f33ea0SBaptiste Daroussin long check = strtol(buf, &next, 0);
550f4f33ea0SBaptiste Daroussin if (next != 0 &&
551f4f33ea0SBaptiste Daroussin next != buf &&
552f4f33ea0SBaptiste Daroussin *next == '\n') {
553f4f33ea0SBaptiste Daroussin result = (int) check;
554f4f33ea0SBaptiste Daroussin }
555f4f33ea0SBaptiste Daroussin break;
556f4f33ea0SBaptiste Daroussin }
557f4f33ea0SBaptiste Daroussin }
558f4f33ea0SBaptiste Daroussin pclose(fp);
559f4f33ea0SBaptiste Daroussin }
560f4f33ea0SBaptiste Daroussin return result;
561f4f33ea0SBaptiste Daroussin }
562f4f33ea0SBaptiste Daroussin #endif
563f4f33ea0SBaptiste Daroussin
564f4f33ea0SBaptiste Daroussin static int
WeekStart(void)565f4f33ea0SBaptiste Daroussin WeekStart(void)
566f4f33ea0SBaptiste Daroussin {
567f4f33ea0SBaptiste Daroussin int result = 0;
568f4f33ea0SBaptiste Daroussin char *option = dialog_vars.week_start;
569f4f33ea0SBaptiste Daroussin if (option != 0) {
570f4f33ea0SBaptiste Daroussin if (option[0]) {
571f4f33ea0SBaptiste Daroussin char *next = 0;
572f4f33ea0SBaptiste Daroussin long check = strtol(option, &next, 0);
573f4f33ea0SBaptiste Daroussin if (next == 0 ||
574f4f33ea0SBaptiste Daroussin next == option ||
575f4f33ea0SBaptiste Daroussin *next != '\0') {
576f4f33ea0SBaptiste Daroussin if (!strcmp(option, "locale")) {
577f4f33ea0SBaptiste Daroussin #if defined(ENABLE_NLS) && defined(HAVE_NL_LANGINFO_1STDAY)
578f4f33ea0SBaptiste Daroussin /*
579f4f33ea0SBaptiste Daroussin * glibc-specific.
580f4f33ea0SBaptiste Daroussin */
581f4f33ea0SBaptiste Daroussin int first_day = nl_langinfo(_NL_TIME_FIRST_WEEKDAY)[0];
582f4f33ea0SBaptiste Daroussin char *basis_ptr = nl_langinfo(_NL_TIME_WEEK_1STDAY);
583f4f33ea0SBaptiste Daroussin int basis_day = (int) (intptr_t) basis_ptr;
584f4f33ea0SBaptiste Daroussin #elif defined(HAVE_DLG_GAUGE)
585f4f33ea0SBaptiste Daroussin /*
586f4f33ea0SBaptiste Daroussin * probably Linux-specific, but harmless otherwise. When
587f4f33ea0SBaptiste Daroussin * available, the locale program will return a single
588f4f33ea0SBaptiste Daroussin * integer on one line.
589f4f33ea0SBaptiste Daroussin */
590f4f33ea0SBaptiste Daroussin int first_day = read_locale_setting("first_weekday", 0);
591f4f33ea0SBaptiste Daroussin int basis_day = read_locale_setting("week-1stday", 0);
592f4f33ea0SBaptiste Daroussin #endif
593f4f33ea0SBaptiste Daroussin #if (defined(ENABLE_NLS) && defined(HAVE_NL_LANGINFO_1STDAY)) || defined(HAVE_DLG_GAUGE)
594f4f33ea0SBaptiste Daroussin int week_1stday = -1;
595f4f33ea0SBaptiste Daroussin if (basis_day == 19971130)
596f4f33ea0SBaptiste Daroussin week_1stday = 0; /* Sun */
597f4f33ea0SBaptiste Daroussin else if (basis_day == 19971201)
598f4f33ea0SBaptiste Daroussin week_1stday = 1; /* Mon */
599f4f33ea0SBaptiste Daroussin if (week_1stday >= 0) {
600f4f33ea0SBaptiste Daroussin result = first_day - week_1stday - 1;
601f4f33ea0SBaptiste Daroussin }
602f4f33ea0SBaptiste Daroussin #else
603f4f33ea0SBaptiste Daroussin result = 0; /* Sun */
604f4f33ea0SBaptiste Daroussin #endif
605f4f33ea0SBaptiste Daroussin } else {
606f4f33ea0SBaptiste Daroussin int day;
607f4f33ea0SBaptiste Daroussin size_t eql = strlen(option);
608f4f33ea0SBaptiste Daroussin for (day = 0; day < MAX_DAYS; ++day) {
609f4f33ea0SBaptiste Daroussin if (!strncmp(nameOfDayOfWeek(day), option, eql)) {
610f4f33ea0SBaptiste Daroussin result = day;
611f4f33ea0SBaptiste Daroussin break;
612f4f33ea0SBaptiste Daroussin }
613f4f33ea0SBaptiste Daroussin }
614f4f33ea0SBaptiste Daroussin }
615f4f33ea0SBaptiste Daroussin } else if (check < 0) {
616f4f33ea0SBaptiste Daroussin result = -1;
617f4f33ea0SBaptiste Daroussin } else {
618f4f33ea0SBaptiste Daroussin result = (int) (check % MAX_DAYS);
619f4f33ea0SBaptiste Daroussin }
620f4f33ea0SBaptiste Daroussin }
621f4f33ea0SBaptiste Daroussin }
622f4f33ea0SBaptiste Daroussin return result;
623f4f33ea0SBaptiste Daroussin }
624f4f33ea0SBaptiste Daroussin
6254c8945a0SNathan Whitehorn static int
CleanupResult(int code,WINDOW * dialog,char * prompt,DIALOG_VARS * save_vars)6264c8945a0SNathan Whitehorn CleanupResult(int code, WINDOW *dialog, char *prompt, DIALOG_VARS * save_vars)
6274c8945a0SNathan Whitehorn {
628f4f33ea0SBaptiste Daroussin int n;
629f4f33ea0SBaptiste Daroussin
6304c8945a0SNathan Whitehorn if (dialog != 0)
6314c8945a0SNathan Whitehorn dlg_del_window(dialog);
6324c8945a0SNathan Whitehorn dlg_mouse_free_regions();
6334c8945a0SNathan Whitehorn if (prompt != 0)
6344c8945a0SNathan Whitehorn free(prompt);
6354c8945a0SNathan Whitehorn dlg_restore_vars(save_vars);
6364c8945a0SNathan Whitehorn
637f4f33ea0SBaptiste Daroussin for (n = 0; n < MAX_DAYS; ++n) {
638f4f33ea0SBaptiste Daroussin free(cached_days[n]);
639f4f33ea0SBaptiste Daroussin cached_days[n] = 0;
640f4f33ea0SBaptiste Daroussin }
641f4f33ea0SBaptiste Daroussin for (n = 0; n < MAX_MONTHS; ++n) {
642f4f33ea0SBaptiste Daroussin free(cached_months[n]);
643f4f33ea0SBaptiste Daroussin cached_months[n] = 0;
644f4f33ea0SBaptiste Daroussin }
645f4f33ea0SBaptiste Daroussin
6464c8945a0SNathan Whitehorn return code;
6474c8945a0SNathan Whitehorn }
6484c8945a0SNathan Whitehorn
649f4f33ea0SBaptiste Daroussin static void
trace_date(struct tm * current,struct tm * old)650f4f33ea0SBaptiste Daroussin trace_date(struct tm *current, struct tm *old)
651f4f33ea0SBaptiste Daroussin {
652f4f33ea0SBaptiste Daroussin bool changed = (old == 0 ||
653f4f33ea0SBaptiste Daroussin current->tm_mday != old->tm_mday ||
654f4f33ea0SBaptiste Daroussin current->tm_mon != old->tm_mon ||
655f4f33ea0SBaptiste Daroussin current->tm_year != old->tm_year);
656f4f33ea0SBaptiste Daroussin if (changed) {
657f4f33ea0SBaptiste Daroussin DLG_TRACE(("# current %04d/%02d/%02d\n",
658f4f33ea0SBaptiste Daroussin current->tm_year + 1900,
659f4f33ea0SBaptiste Daroussin current->tm_mon + 1,
660f4f33ea0SBaptiste Daroussin current->tm_mday));
661f4f33ea0SBaptiste Daroussin } else {
662f4f33ea0SBaptiste Daroussin DLG_TRACE(("# current (unchanged)\n"));
663f4f33ea0SBaptiste Daroussin }
664f4f33ea0SBaptiste Daroussin }
665f4f33ea0SBaptiste Daroussin
6664c8945a0SNathan Whitehorn #define DrawObject(data) (data)->box_draw(data, ¤t)
6674c8945a0SNathan Whitehorn
6684c8945a0SNathan Whitehorn /*
6694c8945a0SNathan Whitehorn * Display a dialog box for entering a date
6704c8945a0SNathan Whitehorn */
6714c8945a0SNathan Whitehorn int
dialog_calendar(const char * title,const char * subtitle,int height,int width,int day,int month,int year)6724c8945a0SNathan Whitehorn dialog_calendar(const char *title,
6734c8945a0SNathan Whitehorn const char *subtitle,
6744c8945a0SNathan Whitehorn int height,
6754c8945a0SNathan Whitehorn int width,
6764c8945a0SNathan Whitehorn int day,
6774c8945a0SNathan Whitehorn int month,
6784c8945a0SNathan Whitehorn int year)
6794c8945a0SNathan Whitehorn {
6804c8945a0SNathan Whitehorn /* *INDENT-OFF* */
6814c8945a0SNathan Whitehorn static DLG_KEYS_BINDING binding[] = {
682682c9e0fSNathan Whitehorn HELPKEY_BINDINGS,
6834c8945a0SNathan Whitehorn ENTERKEY_BINDINGS,
684f4f33ea0SBaptiste Daroussin TOGGLEKEY_BINDINGS,
6854c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
6864c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
6874c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_DOWN, 'j' ),
6884c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_DOWN, DLGK_MOUSE(KEY_NPAGE) ),
6894c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_DOWN, KEY_DOWN ),
6904c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_DOWN, KEY_NPAGE ),
6914c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_LEFT, '-' ),
6924c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_LEFT, 'h' ),
6934c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_LEFT, CHR_BACKSPACE ),
6944c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_LEFT, CHR_PREVIOUS ),
6954c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_LEFT, KEY_LEFT ),
6964c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_RIGHT, '+' ),
6974c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_RIGHT, 'l' ),
6984c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_RIGHT, CHR_NEXT ),
6994c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_RIGHT, KEY_NEXT ),
7004c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_RIGHT, KEY_RIGHT ),
7014c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_UP, 'k' ),
7024c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_UP, KEY_PPAGE ),
7034c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_UP, KEY_PREVIOUS ),
7044c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_UP, KEY_UP ),
7054c8945a0SNathan Whitehorn DLG_KEYS_DATA( DLGK_GRID_UP, DLGK_MOUSE(KEY_PPAGE) ),
7064c8945a0SNathan Whitehorn END_KEYS_BINDING
7074c8945a0SNathan Whitehorn };
7084c8945a0SNathan Whitehorn /* *INDENT-ON* */
7094c8945a0SNathan Whitehorn
7104c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
7114c8945a0SNathan Whitehorn int old_height = height;
7124c8945a0SNathan Whitehorn int old_width = width;
7134c8945a0SNathan Whitehorn #endif
7144c8945a0SNathan Whitehorn BOX dy_box, mn_box, yr_box;
7154c8945a0SNathan Whitehorn int fkey;
716*a96ef450SBaptiste Daroussin int key;
7174c8945a0SNathan Whitehorn int step;
7184c8945a0SNathan Whitehorn int button;
7194c8945a0SNathan Whitehorn int result = DLG_EXIT_UNKNOWN;
720f4f33ea0SBaptiste Daroussin int week_start;
7214c8945a0SNathan Whitehorn WINDOW *dialog;
722*a96ef450SBaptiste Daroussin time_t now_time;
7234c8945a0SNathan Whitehorn struct tm current;
7242a3e3873SBaptiste Daroussin int state = dlg_default_button();
7254c8945a0SNathan Whitehorn const char **buttons = dlg_ok_labels();
726f4f33ea0SBaptiste Daroussin char *prompt;
7274c8945a0SNathan Whitehorn int mincols = MIN_WIDE;
7284c8945a0SNathan Whitehorn char buffer[MAX_LEN];
7294c8945a0SNathan Whitehorn DIALOG_VARS save_vars;
7304c8945a0SNathan Whitehorn
731f4f33ea0SBaptiste Daroussin DLG_TRACE(("# calendar args:\n"));
732f4f33ea0SBaptiste Daroussin DLG_TRACE2S("title", title);
733f4f33ea0SBaptiste Daroussin DLG_TRACE2S("message", subtitle);
734f4f33ea0SBaptiste Daroussin DLG_TRACE2N("height", height);
735f4f33ea0SBaptiste Daroussin DLG_TRACE2N("width", width);
736f4f33ea0SBaptiste Daroussin DLG_TRACE2N("day", day);
737f4f33ea0SBaptiste Daroussin DLG_TRACE2N("month", month);
738f4f33ea0SBaptiste Daroussin DLG_TRACE2N("year", year);
739f4f33ea0SBaptiste Daroussin
7404c8945a0SNathan Whitehorn dlg_save_vars(&save_vars);
7414c8945a0SNathan Whitehorn dialog_vars.separate_output = TRUE;
7424c8945a0SNathan Whitehorn
7434c8945a0SNathan Whitehorn dlg_does_output();
7444c8945a0SNathan Whitehorn
745f4f33ea0SBaptiste Daroussin /*
746*a96ef450SBaptiste Daroussin * Unless overridden, the current time/date is our starting point.
747f4f33ea0SBaptiste Daroussin */
7484c8945a0SNathan Whitehorn now_time = time((time_t *) 0);
7494c8945a0SNathan Whitehorn current = *localtime(&now_time);
750f4f33ea0SBaptiste Daroussin
751f4f33ea0SBaptiste Daroussin #if HAVE_MKTIME
752f4f33ea0SBaptiste Daroussin current.tm_isdst = -1;
753f4f33ea0SBaptiste Daroussin if (year >= 1900) {
754f4f33ea0SBaptiste Daroussin current.tm_year = year - 1900;
755f4f33ea0SBaptiste Daroussin }
756f4f33ea0SBaptiste Daroussin if (month >= 1) {
757f4f33ea0SBaptiste Daroussin current.tm_mon = month - 1;
758f4f33ea0SBaptiste Daroussin }
759f4f33ea0SBaptiste Daroussin if (day > 0 && day <= days_per_month(current.tm_year + 1900,
760f4f33ea0SBaptiste Daroussin current.tm_mon + 1)) {
761f4f33ea0SBaptiste Daroussin current.tm_mday = day;
762f4f33ea0SBaptiste Daroussin }
763f4f33ea0SBaptiste Daroussin now_time = mktime(¤t);
764f4f33ea0SBaptiste Daroussin #else
7654c8945a0SNathan Whitehorn if (day < 0)
7664c8945a0SNathan Whitehorn day = current.tm_mday;
7674c8945a0SNathan Whitehorn if (month < 0)
7684c8945a0SNathan Whitehorn month = current.tm_mon + 1;
7694c8945a0SNathan Whitehorn if (year < 0)
7704c8945a0SNathan Whitehorn year = current.tm_year + 1900;
7714c8945a0SNathan Whitehorn
7724c8945a0SNathan Whitehorn /* compute a struct tm that matches the day/month/year parameters */
7734c8945a0SNathan Whitehorn if (((year -= 1900) > 0) && (year < 200)) {
7744c8945a0SNathan Whitehorn /* ugly, but I'd like to run this on older machines w/o mktime -TD */
7754c8945a0SNathan Whitehorn for (;;) {
7764c8945a0SNathan Whitehorn if (year > current.tm_year) {
7774c8945a0SNathan Whitehorn now_time += ONE_DAY * days_in_year(¤t, 0);
7784c8945a0SNathan Whitehorn } else if (year < current.tm_year) {
7794c8945a0SNathan Whitehorn now_time -= ONE_DAY * days_in_year(¤t, -1);
7804c8945a0SNathan Whitehorn } else if (month > current.tm_mon + 1) {
7814c8945a0SNathan Whitehorn now_time += ONE_DAY * days_in_month(¤t, 0);
7824c8945a0SNathan Whitehorn } else if (month < current.tm_mon + 1) {
7834c8945a0SNathan Whitehorn now_time -= ONE_DAY * days_in_month(¤t, -1);
7844c8945a0SNathan Whitehorn } else if (day > current.tm_mday) {
7854c8945a0SNathan Whitehorn now_time += ONE_DAY;
7864c8945a0SNathan Whitehorn } else if (day < current.tm_mday) {
7874c8945a0SNathan Whitehorn now_time -= ONE_DAY;
7884c8945a0SNathan Whitehorn } else {
7894c8945a0SNathan Whitehorn break;
7904c8945a0SNathan Whitehorn }
7914c8945a0SNathan Whitehorn current = *localtime(&now_time);
7924c8945a0SNathan Whitehorn }
7934c8945a0SNathan Whitehorn }
794f4f33ea0SBaptiste Daroussin #endif
795f4f33ea0SBaptiste Daroussin
7964c8945a0SNathan Whitehorn dlg_button_layout(buttons, &mincols);
7974c8945a0SNathan Whitehorn
7984c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
7994c8945a0SNathan Whitehorn retry:
8004c8945a0SNathan Whitehorn #endif
8014c8945a0SNathan Whitehorn
802f4f33ea0SBaptiste Daroussin prompt = dlg_strclone(subtitle);
8034c8945a0SNathan Whitehorn dlg_auto_size(title, prompt, &height, &width, 0, mincols);
804f4f33ea0SBaptiste Daroussin
8054c8945a0SNathan Whitehorn height += MIN_HIGH - 1;
8064c8945a0SNathan Whitehorn dlg_print_size(height, width);
8074c8945a0SNathan Whitehorn dlg_ctl_size(height, width);
8084c8945a0SNathan Whitehorn
8094c8945a0SNathan Whitehorn dialog = dlg_new_window(height, width,
8104c8945a0SNathan Whitehorn dlg_box_y_ordinate(height),
8114c8945a0SNathan Whitehorn dlg_box_x_ordinate(width));
8124c8945a0SNathan Whitehorn dlg_register_window(dialog, "calendar", binding);
8134c8945a0SNathan Whitehorn dlg_register_buttons(dialog, "calendar", buttons);
8144c8945a0SNathan Whitehorn
8154c8945a0SNathan Whitehorn /* mainbox */
8162a3e3873SBaptiste Daroussin dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr);
8172a3e3873SBaptiste Daroussin dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr);
8184c8945a0SNathan Whitehorn dlg_draw_title(dialog, title);
8194c8945a0SNathan Whitehorn
820f4f33ea0SBaptiste Daroussin dlg_attrset(dialog, dialog_attr); /* text mainbox */
8214c8945a0SNathan Whitehorn dlg_print_autowrap(dialog, prompt, height, width);
8224c8945a0SNathan Whitehorn
8234c8945a0SNathan Whitehorn /* compute positions of day, month and year boxes */
8244c8945a0SNathan Whitehorn memset(&dy_box, 0, sizeof(dy_box));
8254c8945a0SNathan Whitehorn memset(&mn_box, 0, sizeof(mn_box));
8264c8945a0SNathan Whitehorn memset(&yr_box, 0, sizeof(yr_box));
8274c8945a0SNathan Whitehorn
828f4f33ea0SBaptiste Daroussin if ((week_start = WeekStart()) < 0 ||
829f4f33ea0SBaptiste Daroussin init_object(&dy_box,
8304c8945a0SNathan Whitehorn dialog,
8314c8945a0SNathan Whitehorn (width - DAY_WIDE) / 2,
8324c8945a0SNathan Whitehorn 1 + (height - (DAY_HIGH + BTN_HIGH + (5 * MARGIN))),
8334c8945a0SNathan Whitehorn DAY_WIDE,
8344c8945a0SNathan Whitehorn DAY_HIGH + 1,
8354c8945a0SNathan Whitehorn draw_day,
836f4f33ea0SBaptiste Daroussin week_start,
837f4f33ea0SBaptiste Daroussin 'D') < 0 ||
838f4f33ea0SBaptiste Daroussin ((dy_box.week_start = WeekStart()) < 0) ||
839f4f33ea0SBaptiste Daroussin DrawObject(&dy_box) < 0) {
8404c8945a0SNathan Whitehorn return CleanupResult(DLG_EXIT_ERROR, dialog, prompt, &save_vars);
8414c8945a0SNathan Whitehorn }
8424c8945a0SNathan Whitehorn
8434c8945a0SNathan Whitehorn if (init_object(&mn_box,
8444c8945a0SNathan Whitehorn dialog,
8454c8945a0SNathan Whitehorn dy_box.x,
8464c8945a0SNathan Whitehorn dy_box.y - (HDR_HIGH + 2 * MARGIN),
8474c8945a0SNathan Whitehorn (DAY_WIDE / 2) - MARGIN,
8484c8945a0SNathan Whitehorn HDR_HIGH,
8494c8945a0SNathan Whitehorn draw_month,
850f4f33ea0SBaptiste Daroussin 0,
8514c8945a0SNathan Whitehorn 'M') < 0
8524c8945a0SNathan Whitehorn || DrawObject(&mn_box) < 0) {
8534c8945a0SNathan Whitehorn return CleanupResult(DLG_EXIT_ERROR, dialog, prompt, &save_vars);
8544c8945a0SNathan Whitehorn }
8554c8945a0SNathan Whitehorn
8564c8945a0SNathan Whitehorn if (init_object(&yr_box,
8574c8945a0SNathan Whitehorn dialog,
8584c8945a0SNathan Whitehorn dy_box.x + mn_box.width + 2,
8594c8945a0SNathan Whitehorn mn_box.y,
8604c8945a0SNathan Whitehorn mn_box.width,
8614c8945a0SNathan Whitehorn mn_box.height,
8624c8945a0SNathan Whitehorn draw_year,
863f4f33ea0SBaptiste Daroussin 0,
8644c8945a0SNathan Whitehorn 'Y') < 0
8654c8945a0SNathan Whitehorn || DrawObject(&yr_box) < 0) {
8664c8945a0SNathan Whitehorn return CleanupResult(DLG_EXIT_ERROR, dialog, prompt, &save_vars);
8674c8945a0SNathan Whitehorn }
8684c8945a0SNathan Whitehorn
8692a3e3873SBaptiste Daroussin dlg_trace_win(dialog);
8704c8945a0SNathan Whitehorn while (result == DLG_EXIT_UNKNOWN) {
871*a96ef450SBaptiste Daroussin int key2;
8724c8945a0SNathan Whitehorn BOX *obj = (state == sDAY ? &dy_box
8734c8945a0SNathan Whitehorn : (state == sMONTH ? &mn_box :
8744c8945a0SNathan Whitehorn (state == sYEAR ? &yr_box : 0)));
8754c8945a0SNathan Whitehorn
8764c8945a0SNathan Whitehorn button = (state < 0) ? 0 : state;
8774c8945a0SNathan Whitehorn dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width);
8784c8945a0SNathan Whitehorn if (obj != 0)
8794c8945a0SNathan Whitehorn dlg_set_focus(dialog, obj->window);
8804c8945a0SNathan Whitehorn
8814c8945a0SNathan Whitehorn key = dlg_mouse_wgetch(dialog, &fkey);
882*a96ef450SBaptiste Daroussin if (dlg_result_key(key, fkey, &result)) {
883*a96ef450SBaptiste Daroussin if (!dlg_button_key(result, &button, &key, &fkey))
8844c8945a0SNathan Whitehorn break;
885*a96ef450SBaptiste Daroussin }
886f4f33ea0SBaptiste Daroussin #define Mouse2Key(key) (key - M_EVENT)
8874c8945a0SNathan Whitehorn if (fkey && (key >= DLGK_MOUSE(KEY_MIN) && key <= DLGK_MOUSE(KEY_MAX))) {
888f4f33ea0SBaptiste Daroussin key = dlg_lookup_key(dialog, Mouse2Key(key), &fkey);
8894c8945a0SNathan Whitehorn }
8904c8945a0SNathan Whitehorn
8914c8945a0SNathan Whitehorn if ((key2 = dlg_char_to_button(key, buttons)) >= 0) {
8924c8945a0SNathan Whitehorn result = key2;
8934c8945a0SNathan Whitehorn } else if (fkey) {
8944c8945a0SNathan Whitehorn /* handle function-keys */
8954c8945a0SNathan Whitehorn switch (key) {
8964c8945a0SNathan Whitehorn case DLGK_MOUSE('D'):
8974c8945a0SNathan Whitehorn state = sDAY;
8984c8945a0SNathan Whitehorn break;
8994c8945a0SNathan Whitehorn case DLGK_MOUSE('M'):
9004c8945a0SNathan Whitehorn state = sMONTH;
9014c8945a0SNathan Whitehorn break;
9024c8945a0SNathan Whitehorn case DLGK_MOUSE('Y'):
9034c8945a0SNathan Whitehorn state = sYEAR;
9044c8945a0SNathan Whitehorn break;
905f4f33ea0SBaptiste Daroussin case DLGK_TOGGLE:
9064c8945a0SNathan Whitehorn case DLGK_ENTER:
907682c9e0fSNathan Whitehorn result = dlg_enter_buttoncode(button);
9084c8945a0SNathan Whitehorn break;
909*a96ef450SBaptiste Daroussin case DLGK_LEAVE:
910*a96ef450SBaptiste Daroussin result = dlg_ok_buttoncode(button);
911*a96ef450SBaptiste Daroussin break;
9124c8945a0SNathan Whitehorn case DLGK_FIELD_PREV:
9134c8945a0SNathan Whitehorn state = dlg_prev_ok_buttonindex(state, sMONTH);
9144c8945a0SNathan Whitehorn break;
9154c8945a0SNathan Whitehorn case DLGK_FIELD_NEXT:
9164c8945a0SNathan Whitehorn state = dlg_next_ok_buttonindex(state, sMONTH);
9174c8945a0SNathan Whitehorn break;
9184c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
9194c8945a0SNathan Whitehorn case KEY_RESIZE:
920f4f33ea0SBaptiste Daroussin dlg_will_resize(dialog);
9214c8945a0SNathan Whitehorn /* reset data */
9224c8945a0SNathan Whitehorn height = old_height;
9234c8945a0SNathan Whitehorn width = old_width;
924f4f33ea0SBaptiste Daroussin free(prompt);
925*a96ef450SBaptiste Daroussin _dlg_resize_cleanup(dialog);
926f4f33ea0SBaptiste Daroussin /* repaint */
9274c8945a0SNathan Whitehorn goto retry;
9284c8945a0SNathan Whitehorn #endif
9294c8945a0SNathan Whitehorn default:
9304c8945a0SNathan Whitehorn step = 0;
9314c8945a0SNathan Whitehorn key2 = -1;
9324c8945a0SNathan Whitehorn if (is_DLGK_MOUSE(key)) {
933f4f33ea0SBaptiste Daroussin if ((key2 = dlg_ok_buttoncode(Mouse2Key(key))) >= 0) {
9344c8945a0SNathan Whitehorn result = key2;
9354c8945a0SNathan Whitehorn break;
9364c8945a0SNathan Whitehorn } else if (key >= DLGK_MOUSE(KEY_MAX)) {
9374c8945a0SNathan Whitehorn state = sDAY;
9384c8945a0SNathan Whitehorn obj = &dy_box;
9394c8945a0SNathan Whitehorn key2 = 1;
9404c8945a0SNathan Whitehorn step = (key
9414c8945a0SNathan Whitehorn - DLGK_MOUSE(KEY_MAX)
9424c8945a0SNathan Whitehorn - day_cell_number(¤t));
943f4f33ea0SBaptiste Daroussin DLG_TRACE(("# mouseclick decoded %d\n", step));
9444c8945a0SNathan Whitehorn }
9454c8945a0SNathan Whitehorn }
9464c8945a0SNathan Whitehorn if (obj != 0) {
947f4f33ea0SBaptiste Daroussin if (key2 < 0) {
9484c8945a0SNathan Whitehorn step = next_or_previous(key, (obj == &dy_box));
949f4f33ea0SBaptiste Daroussin }
9504c8945a0SNathan Whitehorn if (step != 0) {
9514c8945a0SNathan Whitehorn struct tm old = current;
9524c8945a0SNathan Whitehorn
9534c8945a0SNathan Whitehorn /* see comment regarding mktime -TD */
9544c8945a0SNathan Whitehorn if (obj == &dy_box) {
9554c8945a0SNathan Whitehorn now_time += ONE_DAY * step;
9564c8945a0SNathan Whitehorn } else if (obj == &mn_box) {
9574c8945a0SNathan Whitehorn if (step > 0)
9584c8945a0SNathan Whitehorn now_time += ONE_DAY *
9594c8945a0SNathan Whitehorn days_in_month(¤t, 0);
9604c8945a0SNathan Whitehorn else
9614c8945a0SNathan Whitehorn now_time -= ONE_DAY *
9624c8945a0SNathan Whitehorn days_in_month(¤t, -1);
9634c8945a0SNathan Whitehorn } else if (obj == &yr_box) {
9644c8945a0SNathan Whitehorn if (step > 0)
9654c8945a0SNathan Whitehorn now_time += (ONE_DAY
9664c8945a0SNathan Whitehorn * days_in_year(¤t, 0));
9674c8945a0SNathan Whitehorn else
9684c8945a0SNathan Whitehorn now_time -= (ONE_DAY
9694c8945a0SNathan Whitehorn * days_in_year(¤t, -1));
9704c8945a0SNathan Whitehorn }
9714c8945a0SNathan Whitehorn
9724c8945a0SNathan Whitehorn current = *localtime(&now_time);
9734c8945a0SNathan Whitehorn
974f4f33ea0SBaptiste Daroussin trace_date(¤t, &old);
9754c8945a0SNathan Whitehorn if (obj != &dy_box
9764c8945a0SNathan Whitehorn && (current.tm_mday != old.tm_mday
9774c8945a0SNathan Whitehorn || current.tm_mon != old.tm_mon
9784c8945a0SNathan Whitehorn || current.tm_year != old.tm_year))
9794c8945a0SNathan Whitehorn DrawObject(&dy_box);
9804c8945a0SNathan Whitehorn if (obj != &mn_box && current.tm_mon != old.tm_mon)
9814c8945a0SNathan Whitehorn DrawObject(&mn_box);
9824c8945a0SNathan Whitehorn if (obj != &yr_box && current.tm_year != old.tm_year)
9834c8945a0SNathan Whitehorn DrawObject(&yr_box);
9844c8945a0SNathan Whitehorn (void) DrawObject(obj);
9854c8945a0SNathan Whitehorn }
9864c8945a0SNathan Whitehorn } else if (state >= 0) {
9874c8945a0SNathan Whitehorn if (next_or_previous(key, FALSE) < 0)
9884c8945a0SNathan Whitehorn state = dlg_prev_ok_buttonindex(state, sMONTH);
9894c8945a0SNathan Whitehorn else if (next_or_previous(key, FALSE) > 0)
9904c8945a0SNathan Whitehorn state = dlg_next_ok_buttonindex(state, sMONTH);
9914c8945a0SNathan Whitehorn }
9924c8945a0SNathan Whitehorn break;
9934c8945a0SNathan Whitehorn }
9944c8945a0SNathan Whitehorn }
9954c8945a0SNathan Whitehorn }
9964c8945a0SNathan Whitehorn
9974c8945a0SNathan Whitehorn #define DefaultFormat(dst, src) \
9984c8945a0SNathan Whitehorn sprintf(dst, "%02d/%02d/%0d", \
9994c8945a0SNathan Whitehorn src.tm_mday, src.tm_mon + 1, src.tm_year + 1900)
10004c8945a0SNathan Whitehorn #ifdef HAVE_STRFTIME
10014c8945a0SNathan Whitehorn if (dialog_vars.date_format != 0) {
10024c8945a0SNathan Whitehorn size_t used = strftime(buffer,
10034c8945a0SNathan Whitehorn sizeof(buffer) - 1,
10044c8945a0SNathan Whitehorn dialog_vars.date_format,
10054c8945a0SNathan Whitehorn ¤t);
10064c8945a0SNathan Whitehorn if (used == 0 || *buffer == '\0')
10074c8945a0SNathan Whitehorn DefaultFormat(buffer, current);
10084c8945a0SNathan Whitehorn } else
10094c8945a0SNathan Whitehorn #endif
10104c8945a0SNathan Whitehorn DefaultFormat(buffer, current);
10114c8945a0SNathan Whitehorn
10124c8945a0SNathan Whitehorn dlg_add_result(buffer);
1013*a96ef450SBaptiste Daroussin AddLastKey();
10144c8945a0SNathan Whitehorn
10154c8945a0SNathan Whitehorn return CleanupResult(result, dialog, prompt, &save_vars);
10164c8945a0SNathan Whitehorn }
1017