813 lines
19 KiB
C
813 lines
19 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
calendar.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements the calendar control for the Date/Time applet.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Include Files.
|
||
|
//
|
||
|
|
||
|
#include "timedate.h"
|
||
|
#include "rc.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Constant Declarations.
|
||
|
//
|
||
|
|
||
|
#define DEF_FIRST_WEEKDAY (6)
|
||
|
|
||
|
#define cBorderX 5
|
||
|
#define cBorderY 3
|
||
|
#define cBorderSelect 1
|
||
|
|
||
|
#define IS_FE_LANGUAGE(p) (((p) == LANG_CHINESE) || \
|
||
|
((p) == LANG_JAPANESE) || \
|
||
|
((p) == LANG_KOREAN))
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Typedef Declarations.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Struture for global data.
|
||
|
//
|
||
|
typedef struct _CALINFO
|
||
|
{
|
||
|
HWND hwnd; // the hwnd
|
||
|
HFONT hfontCal; // the font to use
|
||
|
BOOL fFocus; // do we have the focus
|
||
|
int cxBlank; // size of a blank
|
||
|
int cxChar; // the width of digits
|
||
|
int cyChar; // the height of digits
|
||
|
} CALINFO, *PCALINFO;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetFirstDayOfAnyWeek
|
||
|
//
|
||
|
// For this function ONLY:
|
||
|
// 0 = Monday
|
||
|
// 6 = Sunday
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int GetFirstDayOfAnyWeek()
|
||
|
{
|
||
|
static int iDay = -1;
|
||
|
|
||
|
if (iDay < 0)
|
||
|
{
|
||
|
TCHAR ch[2] = { 0 };
|
||
|
|
||
|
*ch = TEXT('0') + DEF_FIRST_WEEKDAY;
|
||
|
|
||
|
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, ch, 2);
|
||
|
|
||
|
iDay = ( ((*ch >= TEXT('0')) && (*ch <= TEXT('6')))
|
||
|
? ((int)*ch - TEXT('0'))
|
||
|
: DEF_FIRST_WEEKDAY );
|
||
|
}
|
||
|
|
||
|
return (iDay);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetLocalWeekday
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int GetLocalWeekday()
|
||
|
{
|
||
|
//
|
||
|
// Convert local first day to 0==sunday and subtract from today.
|
||
|
//
|
||
|
return ((wDateTime[WEEKDAY] + 7 - ((GetFirstDayOfAnyWeek() + 1) % 7)) % 7);
|
||
|
}
|
||
|
|
||
|
void DetermineDayOfWeek()
|
||
|
{
|
||
|
FILETIME FileTime;
|
||
|
SYSTEMTIME SystemTime;
|
||
|
|
||
|
SystemTime.wHour = wDateTime[HOUR];
|
||
|
SystemTime.wMinute = wDateTime[MINUTE];
|
||
|
SystemTime.wSecond = wDateTime[SECOND];
|
||
|
|
||
|
SystemTime.wMilliseconds = 0;
|
||
|
|
||
|
SystemTime.wMonth = wDateTime[MONTH];
|
||
|
SystemTime.wDay = wDateTime[DAY];
|
||
|
SystemTime.wYear = wDateTime[YEAR];
|
||
|
SystemTimeToFileTime(&SystemTime, &FileTime);
|
||
|
FileTimeToSystemTime(&FileTime, &SystemTime);
|
||
|
wDateTime[WEEKDAY] = SystemTime.wDayOfWeek;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetFirstDayOfTheMonth
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int GetFirstDayOfTheMonth()
|
||
|
{
|
||
|
DetermineDayOfWeek();
|
||
|
return ((GetLocalWeekday() + 8 - (wDateTime[DAY] % 7)) % 7);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetDaysOfTheMonth
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int GetDaysOfTheMonth(
|
||
|
int iMonth)
|
||
|
{
|
||
|
int cDays;
|
||
|
int nYear;
|
||
|
|
||
|
//
|
||
|
// Calculate the number of days in the current month -
|
||
|
// add one if this is a leap year and the month is February.
|
||
|
//
|
||
|
if (iMonth <= 7)
|
||
|
{
|
||
|
cDays = 30 + (iMonth % 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cDays = 31 - (iMonth % 2);
|
||
|
}
|
||
|
|
||
|
if (iMonth == 2)
|
||
|
{
|
||
|
cDays = 28;
|
||
|
nYear = wDateTime[YEAR];
|
||
|
if ((nYear % 4 == 0) && ((nYear % 100 != 0) || (nYear % 400 == 0)))
|
||
|
{
|
||
|
cDays++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (cDays);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// AdjustDeltaDay
|
||
|
//
|
||
|
// Adjust the day part of the current date
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void AdjustDeltaDay(
|
||
|
HWND hwnd,
|
||
|
int iDay)
|
||
|
{
|
||
|
GetTime();
|
||
|
|
||
|
if (wDateTime[DAY] != iDay)
|
||
|
{
|
||
|
wPrevDateTime[DAY] = wDateTime[DAY] = (WORD)iDay;
|
||
|
fDateDirty = TRUE;
|
||
|
|
||
|
//
|
||
|
// Let our parent know that we changed.
|
||
|
//
|
||
|
FORWARD_WM_COMMAND( GetParent(hwnd),
|
||
|
GetWindowLong(hwnd, GWL_ID),
|
||
|
hwnd,
|
||
|
CBN_SELCHANGE,
|
||
|
SendMessage );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int GetCalendarName(LPTSTR pszName, int cch)
|
||
|
{
|
||
|
TCHAR szDateString[100];
|
||
|
SYSTEMTIME SystemTime;
|
||
|
int cchResult = 0;
|
||
|
|
||
|
SystemTime.wHour = wDateTime[HOUR];
|
||
|
SystemTime.wMinute = wDateTime[MINUTE];
|
||
|
SystemTime.wSecond = wDateTime[SECOND];
|
||
|
|
||
|
SystemTime.wMilliseconds = 0;
|
||
|
|
||
|
SystemTime.wMonth = wDateTime[MONTH];
|
||
|
SystemTime.wDay = wDateTime[DAY];
|
||
|
SystemTime.wYear = wDateTime[YEAR];
|
||
|
|
||
|
if (0 != GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE,
|
||
|
&SystemTime, NULL, szDateString, ARRAYSIZE(szDateString)))
|
||
|
{
|
||
|
if (pszName)
|
||
|
lstrcpyn( pszName, szDateString, cch);
|
||
|
|
||
|
cchResult = lstrlen(szDateString);
|
||
|
}
|
||
|
|
||
|
return cchResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// ChangeCurrentDate
|
||
|
//
|
||
|
// If we pass in iNewCol < 0, we simply want to invalidate todays date.
|
||
|
// This is used when we gain and lose focus.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void ChangeCurrentDate(
|
||
|
PCALINFO pci,
|
||
|
int iNewCol,
|
||
|
int iNewRow)
|
||
|
{
|
||
|
int iFirstDay, iRow, iColumn;
|
||
|
RECT rc, rcT;
|
||
|
|
||
|
GetClientRect(pci->hwnd, &rc);
|
||
|
iFirstDay = GetFirstDayOfTheMonth();
|
||
|
iColumn = (wDateTime[DAY] - 1 + iFirstDay) % 7;
|
||
|
iRow = 1 + ((wDateTime[DAY] - 1 + iFirstDay) / 7);
|
||
|
|
||
|
rcT.left = (((rc.right - rc.left) * iColumn) / 7) + cBorderX - cBorderSelect;
|
||
|
rcT.right = rcT.left + (pci->cxChar * 2) + (2 * cBorderSelect);
|
||
|
rcT.top = ((rc.bottom - rc.top) * iRow ) / 7 + cBorderY - cBorderSelect;
|
||
|
rcT.bottom = rcT.top + pci->cyChar + (2 * cBorderSelect);
|
||
|
|
||
|
InvalidateRect(pci->hwnd, &rcT, FALSE);
|
||
|
|
||
|
if (iNewCol >= 0)
|
||
|
{
|
||
|
AdjustDeltaDay(pci->hwnd, ((iNewRow - 1) * 7) + iNewCol + 1 - iFirstDay);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// CalendarPaint
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
#define NUM_DBCS_CHARS 1 // 1 Unicode char
|
||
|
#else
|
||
|
#define NUM_DBCS_CHARS 2 // 1 lead byte, 1 trail byte
|
||
|
#endif
|
||
|
|
||
|
BOOL CalendarPaint(
|
||
|
PCALINFO pci,
|
||
|
HWND hwnd)
|
||
|
{
|
||
|
RECT rc, rcT;
|
||
|
PAINTSTRUCT ps;
|
||
|
HDC hdc;
|
||
|
int iWeek, iWeekDay, iDay, iMaxDays;
|
||
|
int iFirstDayOfWeek, iFirstDayOfMonth;
|
||
|
TCHAR pszDate[3];
|
||
|
TCHAR szShortDay[25];
|
||
|
DWORD dwbkColor;
|
||
|
COLORREF o_TextColor;
|
||
|
LCID Locale;
|
||
|
LANGID LangID = GetUserDefaultLangID();
|
||
|
BOOL IsFELang = IS_FE_LANGUAGE(PRIMARYLANGID(LangID));
|
||
|
|
||
|
iFirstDayOfMonth = GetFirstDayOfTheMonth();
|
||
|
iMaxDays = GetDaysOfTheMonth(wDateTime[MONTH]);
|
||
|
iDay = 1;
|
||
|
pszDate[0] = TEXT(' ');
|
||
|
pszDate[1] = TEXT('0');
|
||
|
|
||
|
//
|
||
|
// Paint the background of the dates page.
|
||
|
//
|
||
|
hdc = BeginPaint(hwnd, &ps);
|
||
|
GetClientRect(hwnd, &rc);
|
||
|
FillRect(hdc, &rc, GetSysColorBrush(COLOR_WINDOW));
|
||
|
|
||
|
//
|
||
|
// The day specifier.
|
||
|
//
|
||
|
rcT.left = rc.left;
|
||
|
rcT.right = rc.right;
|
||
|
rcT.top = rc.top;
|
||
|
rcT.bottom = rc.top + ((rc.bottom - rc.top) / 7);
|
||
|
FillRect(hdc, &rcT, GetSysColorBrush(COLOR_INACTIVECAPTION));
|
||
|
|
||
|
//
|
||
|
// Fill the page.
|
||
|
//
|
||
|
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
|
||
|
SelectFont(hdc, pci->hfontCal);
|
||
|
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
|
||
|
|
||
|
//
|
||
|
// See if we need to calculate the size of characters.
|
||
|
//
|
||
|
if (pci->cxChar == 0)
|
||
|
{
|
||
|
DrawText(hdc, TEXT("0"), 1, &rcT, DT_CALCRECT);
|
||
|
pci->cxChar = rcT.right - rcT.left;
|
||
|
pci->cyChar = rcT.bottom - rcT.top;
|
||
|
|
||
|
DrawText(hdc, TEXT(" "), 1, &rcT, DT_CALCRECT);
|
||
|
pci->cxBlank = rcT.right - rcT.left;
|
||
|
}
|
||
|
|
||
|
for (iWeek = 1; (iWeek < 7); iWeek++)
|
||
|
{
|
||
|
for (iWeekDay = iFirstDayOfMonth;
|
||
|
(iWeekDay < 7) && (iDay <= iMaxDays);
|
||
|
iWeekDay++)
|
||
|
{
|
||
|
rcT.left = ((((rc.right - rc.left) * iWeekDay) / 7)) + cBorderX;
|
||
|
rcT.top = (((rc.bottom - rc.top) * iWeek) / 7) + cBorderY;
|
||
|
rcT.right = rcT.left + 20;
|
||
|
rcT.bottom = rcT.top + 20;
|
||
|
|
||
|
if (pszDate[1] == TEXT('9'))
|
||
|
{
|
||
|
pszDate[1] = TEXT('0');
|
||
|
|
||
|
if (pszDate[0] == TEXT(' '))
|
||
|
{
|
||
|
pszDate[0] = TEXT('1');
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pszDate[0] = pszDate[0] + 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pszDate[1] = pszDate[1] + 1;
|
||
|
}
|
||
|
|
||
|
if (wDateTime[DAY] == iDay)
|
||
|
{
|
||
|
dwbkColor = GetBkColor(hdc);
|
||
|
SetBkColor(hdc, GetSysColor(COLOR_ACTIVECAPTION));
|
||
|
o_TextColor = GetTextColor(hdc);
|
||
|
SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
|
||
|
}
|
||
|
|
||
|
ExtTextOut( hdc,
|
||
|
rcT.left,
|
||
|
rcT.top,
|
||
|
0,
|
||
|
&rcT,
|
||
|
(LPTSTR)pszDate,
|
||
|
2,
|
||
|
NULL );
|
||
|
|
||
|
//
|
||
|
// If we drew it inverted - put it back.
|
||
|
//
|
||
|
if (wDateTime[DAY] == iDay)
|
||
|
{
|
||
|
//
|
||
|
// If we have the focus we also need to draw the focus
|
||
|
// rectangle for this item.
|
||
|
//
|
||
|
if (pci->fFocus)
|
||
|
{
|
||
|
rcT.bottom = rcT.top + pci->cyChar;
|
||
|
|
||
|
if (iDay <= 9)
|
||
|
{
|
||
|
rcT.right = rcT.left + pci->cxChar + pci->cxBlank;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rcT.right = rcT.left + 2 * pci->cxChar;
|
||
|
}
|
||
|
|
||
|
DrawFocusRect(hdc, &rcT);
|
||
|
}
|
||
|
|
||
|
SetBkColor(hdc, dwbkColor);
|
||
|
SetTextColor(hdc, o_TextColor);
|
||
|
}
|
||
|
|
||
|
iFirstDayOfMonth = 0;
|
||
|
iDay++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the FONT color for the SMTWTFS line.
|
||
|
//
|
||
|
dwbkColor = SetBkColor(hdc, GetSysColor(COLOR_INACTIVECAPTION));
|
||
|
SetTextColor(hdc, GetSysColor(COLOR_INACTIVECAPTIONTEXT));
|
||
|
|
||
|
iFirstDayOfWeek = GetFirstDayOfAnyWeek();
|
||
|
|
||
|
if (!IsFELang)
|
||
|
{
|
||
|
//
|
||
|
// Not a FE locale.
|
||
|
//
|
||
|
// If it's Arabic or Syriac, then we want to use the US locale to get the
|
||
|
// first letter of the abbreviated day name to display in the calendar.
|
||
|
//
|
||
|
Locale = ((PRIMARYLANGID(LangID) == LANG_ARABIC) || (PRIMARYLANGID(LangID) == LANG_SYRIAC))
|
||
|
? MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT)
|
||
|
: LOCALE_USER_DEFAULT;
|
||
|
|
||
|
for (iWeekDay = 0; (iWeekDay < 7); iWeekDay++)
|
||
|
{
|
||
|
GetLocaleInfo( Locale,
|
||
|
LOCALE_SABBREVDAYNAME1 + (iWeekDay + iFirstDayOfWeek) % 7,
|
||
|
szShortDay,
|
||
|
sizeof(szShortDay) / sizeof(TCHAR) );
|
||
|
|
||
|
if (*szShortDay)
|
||
|
{
|
||
|
*szShortDay = (TCHAR)CharUpper((LPTSTR)(DWORD_PTR)*szShortDay);
|
||
|
}
|
||
|
|
||
|
TextOut( hdc,
|
||
|
(((rc.right - rc.left) * iWeekDay) / 7) + cBorderX,
|
||
|
cBorderY,
|
||
|
szShortDay,
|
||
|
1 );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// FE Locale.
|
||
|
//
|
||
|
for (iWeekDay = 0; (iWeekDay < 7); iWeekDay++)
|
||
|
{
|
||
|
GetLocaleInfo( LOCALE_USER_DEFAULT,
|
||
|
LOCALE_SABBREVDAYNAME1 + (iWeekDay + iFirstDayOfWeek) % 7,
|
||
|
szShortDay,
|
||
|
sizeof(szShortDay) / sizeof(TCHAR) );
|
||
|
|
||
|
#ifndef UNICODE
|
||
|
if (*szShortDay && !IsDBCSLeadByte(*szShortDay))
|
||
|
#else
|
||
|
if (*szShortDay)
|
||
|
#endif
|
||
|
{
|
||
|
*szShortDay = (TCHAR)CharUpper((LPTSTR)(DWORD_PTR)*szShortDay);
|
||
|
}
|
||
|
|
||
|
if ((PRIMARYLANGID(LangID) == LANG_CHINESE) &&
|
||
|
(lstrlen(szShortDay) == 3 * NUM_DBCS_CHARS))
|
||
|
{
|
||
|
TextOut( hdc,
|
||
|
(((rc.right - rc.left) * iWeekDay) / 7) + cBorderX,
|
||
|
cBorderY,
|
||
|
(LangID == MAKELANGID( LANG_CHINESE,
|
||
|
SUBLANG_CHINESE_HONGKONG ))
|
||
|
? szShortDay
|
||
|
: szShortDay + (2 * NUM_DBCS_CHARS),
|
||
|
1 * NUM_DBCS_CHARS );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TextOut( hdc,
|
||
|
(((rc.right - rc.left) * iWeekDay) / 7) + cBorderX,
|
||
|
cBorderY,
|
||
|
szShortDay,
|
||
|
lstrlen(szShortDay) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetBkColor(hdc, dwbkColor);
|
||
|
EndPaint(hwnd, &ps);
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// IsValidClick
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL IsValidClick(
|
||
|
HWND hwnd,
|
||
|
int x,
|
||
|
int y)
|
||
|
{
|
||
|
int iT;
|
||
|
|
||
|
if (y == 0)
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
iT = GetFirstDayOfTheMonth();
|
||
|
|
||
|
if ((y == 1) && (x < iT))
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
iT += GetDaysOfTheMonth(wDateTime[MONTH]) - 1;
|
||
|
|
||
|
if (y > ((iT / 7) + 1))
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
if ((y == ((iT / 7) + 1)) && (x > (iT % 7)))
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// HandleDateChange
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL HandleDateChange(
|
||
|
PCALINFO pci,
|
||
|
int x,
|
||
|
int y)
|
||
|
{
|
||
|
RECT rc, rcT;
|
||
|
int ix, iy;
|
||
|
|
||
|
GetClientRect(pci->hwnd, &rc);
|
||
|
|
||
|
ix = (x * 7) / (rc.right - rc.left);
|
||
|
iy = (y * 7) / (rc.bottom - rc.top);
|
||
|
|
||
|
if (IsValidClick(pci->hwnd, ix, iy))
|
||
|
{
|
||
|
rcT.left = (((rc.right - rc.left) * ix)/ 7) + cBorderX - cBorderSelect;
|
||
|
rcT.right = rcT.left + (2 * pci->cxChar) + (2 * cBorderSelect);
|
||
|
rcT.top = ((rc.bottom - rc.top) * iy) / 7 + cBorderY - cBorderSelect;
|
||
|
rcT.bottom = rcT.top + pci->cyChar + (2 * cBorderSelect);
|
||
|
|
||
|
InvalidateRect(pci->hwnd, &rcT, FALSE);
|
||
|
ChangeCurrentDate( pci,
|
||
|
(x * 7) / (rc.right - rc.left),
|
||
|
(y * 7) / (rc.bottom - rc.top) );
|
||
|
|
||
|
NotifyWinEvent(EVENT_OBJECT_NAMECHANGE , pci->hwnd, OBJID_WINDOW, CHILDID_SELF);
|
||
|
return (TRUE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// HandleKeyDown
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
void HandleKeyDown(
|
||
|
PCALINFO pci,
|
||
|
int vk,
|
||
|
LPARAM lParam)
|
||
|
{
|
||
|
RECT rcT;
|
||
|
|
||
|
//
|
||
|
// First thing, lets try to figure out what the current x and y is.
|
||
|
//
|
||
|
int ix = GetLocalWeekday();
|
||
|
int iy = (wDateTime[DAY] + GetFirstDayOfTheMonth() - 1) / 7;
|
||
|
|
||
|
switch (vk)
|
||
|
{
|
||
|
case ( VK_LEFT ) :
|
||
|
{
|
||
|
ix--;
|
||
|
if (ix < 0)
|
||
|
{
|
||
|
ix = 6;
|
||
|
iy--;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case ( VK_RIGHT ) :
|
||
|
{
|
||
|
ix++;
|
||
|
if (ix == 7)
|
||
|
{
|
||
|
ix = 0;
|
||
|
iy++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case ( VK_UP ) :
|
||
|
{
|
||
|
iy--;
|
||
|
break;
|
||
|
}
|
||
|
case ( VK_DOWN ) :
|
||
|
{
|
||
|
iy++;
|
||
|
break;
|
||
|
}
|
||
|
default :
|
||
|
{
|
||
|
//
|
||
|
// Ignore the character.
|
||
|
//
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The y's are offset for the days of the week.
|
||
|
//
|
||
|
iy++;
|
||
|
if (!IsValidClick(pci->hwnd, ix, iy))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GetClientRect(pci->hwnd, &rcT);
|
||
|
rcT.left = ((rcT.right * ix) / 7) + cBorderX - cBorderSelect;
|
||
|
rcT.right = rcT.left + (2 * pci->cxChar) + (2 * cBorderSelect);
|
||
|
rcT.top = (rcT.bottom * iy) / 7 + cBorderY - cBorderSelect;
|
||
|
rcT.bottom = rcT.top + pci->cyChar + (2 * cBorderSelect);
|
||
|
|
||
|
InvalidateRect(pci->hwnd, &rcT, FALSE);
|
||
|
|
||
|
//
|
||
|
// First try, simply call to change the date.
|
||
|
//
|
||
|
ChangeCurrentDate(pci, ix, iy);
|
||
|
NotifyWinEvent(EVENT_OBJECT_NAMECHANGE , pci->hwnd, OBJID_WINDOW, CHILDID_SELF);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// CalWndProc
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
LRESULT CALLBACK CalWndProc(
|
||
|
HWND hwnd,
|
||
|
UINT message,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam)
|
||
|
{
|
||
|
PCALINFO pci;
|
||
|
|
||
|
pci = (PCALINFO)GetWindowLongPtr(hwnd, 0);
|
||
|
|
||
|
switch (message)
|
||
|
{
|
||
|
case ( WM_CREATE ) :
|
||
|
{
|
||
|
pci = (PCALINFO)LocalAlloc(LPTR, sizeof(CALINFO));
|
||
|
if (pci == 0)
|
||
|
{
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
pci->hwnd = hwnd;
|
||
|
SetWindowLongPtr(hwnd, 0, (LONG_PTR)pci);
|
||
|
|
||
|
GetDate();
|
||
|
break;
|
||
|
}
|
||
|
case ( WM_NCDESTROY ) :
|
||
|
{
|
||
|
if (pci)
|
||
|
{
|
||
|
LocalFree((HLOCAL)pci);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case ( WM_SETFONT ) :
|
||
|
{
|
||
|
if (wParam)
|
||
|
{
|
||
|
pci->hfontCal = (HFONT)wParam;
|
||
|
pci->cxChar = 0;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case ( WM_GETTEXT ) :
|
||
|
{
|
||
|
return GetCalendarName((LPTSTR)lParam, (int)wParam);
|
||
|
}
|
||
|
case ( WM_GETTEXTLENGTH ) :
|
||
|
{
|
||
|
return GetCalendarName(NULL, 0);
|
||
|
}
|
||
|
case ( WM_PAINT ) :
|
||
|
{
|
||
|
CalendarPaint(pci, hwnd);
|
||
|
break;
|
||
|
}
|
||
|
case ( WM_LBUTTONDOWN ) :
|
||
|
{
|
||
|
SetFocus(hwnd);
|
||
|
HandleDateChange(pci, LOWORD(lParam), HIWORD(lParam));
|
||
|
break;
|
||
|
}
|
||
|
case ( WM_SETFOCUS ) :
|
||
|
{
|
||
|
pci->fFocus = TRUE;
|
||
|
ChangeCurrentDate(pci, -1, -1);
|
||
|
break;
|
||
|
}
|
||
|
case ( WM_KILLFOCUS ) :
|
||
|
{
|
||
|
pci->fFocus = FALSE;
|
||
|
ChangeCurrentDate(pci, -1, -1);
|
||
|
break;
|
||
|
}
|
||
|
case ( WM_KEYDOWN ) :
|
||
|
{
|
||
|
HandleKeyDown(pci, (int)wParam, lParam);
|
||
|
break;
|
||
|
}
|
||
|
case ( WM_GETDLGCODE ) :
|
||
|
{
|
||
|
return (DLGC_WANTARROWS);
|
||
|
break;
|
||
|
}
|
||
|
default :
|
||
|
{
|
||
|
return ( DefWindowProc(hwnd, message, wParam, lParam) );
|
||
|
}
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// CalendarInit
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
TCHAR const c_szCalClass[] = CALENDAR_CLASS;
|
||
|
|
||
|
BOOL CalendarInit(
|
||
|
HANDLE hInstance)
|
||
|
{
|
||
|
WNDCLASS wc;
|
||
|
|
||
|
if (!GetClassInfo(hInstance, c_szCalClass, &wc))
|
||
|
{
|
||
|
wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
|
||
|
wc.cbClsExtra = 0;
|
||
|
wc.cbWndExtra = sizeof(PCALINFO);
|
||
|
wc.hCursor = NULL;
|
||
|
wc.hbrBackground = NULL;
|
||
|
wc.hIcon = NULL;
|
||
|
wc.lpszMenuName = NULL;
|
||
|
wc.lpszClassName = c_szCalClass;
|
||
|
wc.hInstance = hInstance;
|
||
|
wc.lpfnWndProc = CalWndProc;
|
||
|
|
||
|
return (RegisterClass(&wc));
|
||
|
}
|
||
|
return (TRUE);
|
||
|
}
|