Title: Windows Calendar Control Author: Philip J. Erdelsky, 75746.3411@compuserve.com Language: Turbo C/C++ 3.1 for Windows Platform: Windows 3.1 Portability: Other Windows C++ compilers, with slight changes Restrictions: Public domain, no restrictions on use Date: January 9, 1995 Keywords: Windows Custom Control, Calendar, Date Abstract: A windows custom control for date selection. The control shows a single month with the selected day highlighted. The user can change the day, month or year with the mouse or the keyboard. C++ source code only; no VBX file. The "CALENDAR" control is a simple control that you can display wherever the user is required to enter a date. It shows a single month at a time, as a standard tableau with four, five or six lines of numbers as required. The currently selected day is highlighted. When the control is disabled, its border and contents are gray. When the control has the input focus, its border becomes thicker. The user can change the date to another day in the same month by clicking on the desired day. The control will regain the input focus, if necessary, and the highlight will move. The user can change the date to the preceding or following month by clicking on the arrows on either side of the month name. Similarly, the user can change the year to the preceding or following year by clicking on the arrows on either side of the year. When the date is changed in this manner, it always changes to the first day of the month or year. If the control has the input focus, the user can also change the selection with the keyboard. The left and right arrow keys move the date backward or forward one day at a time. The up and down arrow keys move the date backward or forward one week at a time. The PgUp and PgDn keys move the date to the previous or following month, and if the Ctrl key is held down, the PgUp and PgDn keys move the date to the previous or following year. You can put a "CALENDAR" control into a dialog box by including a line of the following form in the appropriate place in the resource (.RC) file: CONTROL 0, control_id, "CALENDAR", WS_CHILD | WS_VISIBLE | WS_TABSTOP, x, y, width, height You can also put a "CALENDAR" control into a dialog box with the Borland Resource Workshop, by selecting a custom control and then entering the class name "CALENDAR" instead of choosing one of the predefined classes. You can also create a "CALENDAR" control dynamically with an appropriate call on CreateWindow(). The control selects the largest font consistent with the specified height and width. Since the font size is not continuously variable, this may leave an unacceptable amount of blank space at the lower and right edges of the control. If this happens, simply reduce the height and width of the control until the excess space shrinks to an acceptable size. The control is initially blank, indicating that no date has been selected. To select an initial date, you must send it a message as follows: SendDlgItemMessage(parent_handle, control_id, CAL_SETDATE, 0, date); A zero date (0L) may be sent to clear the control. The date is a single value of type DWORD with fields as follows: bits 31-16 (the most significant) year bits 15-8 month (1=Jan, 2=Feb, etc.) bits 7-0 (the least significant) day (1-31) Since this control was designed to handle dates in the next century, you must use a four-digit year. The inline function MAKEDATE(), which is defined in the header file CALENDAR.H, can be used to assemble the month, day and year into a date of this form. Three inline functions GETDAY(), GETMONTH() and GETYEAR(), are available to extract the day, month or year from the date. A function called day_of_week() returns a code indicating the day of the week as follows: dow = day_of_week(date); DWORD date; date in format described above unsigned dow; 0 for Sunday, 1 for Monday, etc. The string arrays DAY_NAME[] and MONTH_NAME[] in the file CALENDAR.CPP may be modified for languages other than English. For example, here are the Spanish versions: static char DAY_NAMES[] = "Do Lu Ma Mi Ju Vi Sa"; char *MONTH_NAME[13] = { "???", "ENE", "FEB", "MAR", "AVR", "MAY", "JUN", "JUL", "AGO", "SEP", "OCT", "NOV", "DIC" }; The string array MONTH_NAME[] has been externally defined so other modules can use it to edit dates. To retrieve the date, you simply send the control a different message: date = SendDlgItemMessage(parent_handle, control_id, CAL_GETDATE, 0, 0L); By default, the control accepts only dates between January 1, 1800 and December 31, 2099, inclusive. You can change these limits by sending other messages to the control: SendDlgItemMessage(parent_handle, control_id, CAL_FIRSTDATE, 0, earliest_permitted_date); SendDlgItemMessage(parent_handle, control_id, CAL_LASTDATE, 0, latest_permitted_date); CAUTION: Dates before the adoption of the Gregorian calendar (1752 in England and its colonies) or in the distant future will not be handled properly by the control. The control does not check dates sent to it in messages, either for validity or range. (An invalid date such as February 30 will produce anomalous results, so the calling program should check the date if it comes from a questionable source.) Out-of-range dates are grayed, and if the user attempts to change the date to a new date that is out of range, the control will set the date to the nearest date that is in range. The control sends the notification message CAL_CHANGE to its parent when the user changes the date with either the mouse or keyboard. The control sends the notification message CAL_KILLFOCUS to its parent when it loses the input focus. The file CALENDAR.CPP must be compiled and linked with the rest of the application. The special messages CAL_CHANGE, CAL_FIRSTDATE, CAL_GETDATE, CAL_KILLFOCUS, CAL_LASTDATE and CAL_SETDATE are defined in the header file CALENDAR.H. The files CALTEST.H, CALTEST.CPP and CALTEST.RC contain a simple test program that uses the "CALENDAR" control. The main window contains three calendar controls of different sizes. The program displays the date from the first calendar whenever the date is changed. It displays the date from the second calendar whenever that calendar loses the input focus. The first calendar is limited to dates from January 10, 1980 to January 10, 2000. The other calendars use the default limits.