Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmonthcal.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Timedate Control Panel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: dll/cpl/timedate/monthcal.c 00005 * PURPOSE: Calander implementation 00006 * COPYRIGHT: Copyright 2006 Thomas Weidenmueller <w3seek@reactos.com> 00007 * 00008 */ 00009 00010 #include <timedate.h> 00011 00012 static const WCHAR szMonthCalWndClass[] = L"MonthCalWnd"; 00013 00014 #define MONTHCAL_HEADERBG COLOR_INACTIVECAPTION 00015 #define MONTHCAL_HEADERFG COLOR_INACTIVECAPTIONTEXT 00016 #define MONTHCAL_CTRLBG COLOR_WINDOW 00017 #define MONTHCAL_CTRLFG COLOR_WINDOWTEXT 00018 #define MONTHCAL_SELBG COLOR_ACTIVECAPTION 00019 #define MONTHCAL_SELFG COLOR_CAPTIONTEXT 00020 #define MONTHCAL_DISABLED_HEADERBG COLOR_INACTIVECAPTION 00021 #define MONTHCAL_DISABLED_HEADERFG COLOR_INACTIVECAPTIONTEXT 00022 #define MONTHCAL_DISABLED_CTRLBG COLOR_WINDOW 00023 #define MONTHCAL_DISABLED_CTRLFG COLOR_WINDOWTEXT 00024 #define MONTHCAL_DISABLED_SELBG COLOR_INACTIVECAPTION 00025 #define MONTHCAL_DISABLED_SELFG COLOR_INACTIVECAPTIONTEXT 00026 00027 #define ID_DAYTIMER 1 00028 00029 typedef struct _MONTHCALWND 00030 { 00031 HWND hSelf; 00032 HWND hNotify; 00033 WORD Day; 00034 WORD Month; 00035 WORD Year; 00036 WORD FirstDayOfWeek; 00037 BYTE Days[6][7]; 00038 WCHAR Week[7]; 00039 SIZE CellSize; 00040 SIZE ClientSize; 00041 00042 HFONT hFont; 00043 HBRUSH hbHeader; 00044 HBRUSH hbSelection; 00045 00046 DWORD UIState; 00047 UINT Changed : 1; 00048 UINT DayTimerSet : 1; 00049 UINT Enabled : 1; 00050 UINT HasFocus : 1; 00051 } MONTHCALWND, *PMONTHCALWND; 00052 00053 static LRESULT 00054 MonthCalNotifyControlParent(IN PMONTHCALWND infoPtr, 00055 IN UINT code, 00056 IN OUT PVOID data) 00057 { 00058 LRESULT Ret = 0; 00059 00060 if (infoPtr->hNotify != NULL) 00061 { 00062 LPNMHDR pnmh = (LPNMHDR)data; 00063 00064 pnmh->hwndFrom = infoPtr->hSelf; 00065 pnmh->idFrom = GetWindowLongPtrW(infoPtr->hSelf, 00066 GWLP_ID); 00067 pnmh->code = code; 00068 00069 Ret = SendMessageW(infoPtr->hNotify, 00070 WM_NOTIFY, 00071 (WPARAM)pnmh->idFrom, 00072 (LPARAM)pnmh); 00073 } 00074 00075 return Ret; 00076 } 00077 00078 /* 00079 * For the year range 1..9999 00080 * return 1 if is leap year otherwise 0 00081 */ 00082 static WORD LeapYear(IN WORD Year) 00083 { 00084 return 00085 #ifdef WITH_1752 00086 (Year <= 1752) ? !(Year % 4) : 00087 #endif 00088 !(Year % 4) && ((Year % 100) || !(Year % 400)); 00089 } 00090 00091 static WORD 00092 MonthCalMonthLength(IN WORD Month, 00093 IN WORD Year) 00094 { 00095 const BYTE MonthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}; 00096 00097 if(Month == 2) 00098 return MonthDays[Month - 1] + LeapYear(Year); 00099 else 00100 { 00101 #ifdef WITH_1752 00102 if ((Year == 1752) && (Month == 9)) 00103 return 19; // Special case: September 1752 has no 3rd-13th 00104 else 00105 #endif 00106 return MonthDays[Month - 1]; 00107 } 00108 } 00109 00110 static WORD 00111 MonthCalWeekInMonth(IN WORD Day, 00112 IN WORD DayOfWeek) 00113 { 00114 return (Day - DayOfWeek + 5) / 7; 00115 } 00116 00117 static WORD 00118 MonthCalDayOfWeek(IN PMONTHCALWND infoPtr, 00119 IN WORD Day, 00120 IN WORD Month, 00121 IN WORD Year) 00122 { 00123 const BYTE DayOfWeek[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; 00124 WORD Ret; 00125 00126 Year -= (Month < 3); 00127 Ret = (Year + (Year / 4) - (Year / 100) + (Year / 400) + DayOfWeek[Month - 1] + Day + 6) % 7; 00128 00129 return (7 + Ret - infoPtr->FirstDayOfWeek) % 7; 00130 } 00131 00132 static WORD 00133 MonthCalFirstDayOfWeek(VOID) 00134 { 00135 WCHAR szBuf[2] = {0}; 00136 WORD Ret = 0; 00137 00138 if (GetLocaleInfoW(LOCALE_USER_DEFAULT, 00139 LOCALE_IFIRSTDAYOFWEEK, 00140 szBuf, 00141 sizeof(szBuf) / sizeof(szBuf[0])) != 0) 00142 { 00143 Ret = (WORD)(szBuf[0] - TEXT('0')); 00144 } 00145 00146 return Ret; 00147 } 00148 00149 static BOOL 00150 MonthCalValidDate(IN WORD Day, 00151 IN WORD Month, 00152 IN WORD Year) 00153 { 00154 if (Month < 1 || Month > 12 || 00155 Day == 0 || Day > MonthCalMonthLength(Month, 00156 Year) || 00157 Year < 1899 || Year > 9999) 00158 { 00159 return FALSE; 00160 } 00161 00162 return TRUE; 00163 } 00164 00165 static VOID 00166 MonthCalUpdate(IN PMONTHCALWND infoPtr) 00167 { 00168 PBYTE pDay, pDayEnd; 00169 WORD DayOfWeek, MonthLength, d = 0; 00170 SIZE NewCellSize; 00171 BOOL RepaintHeader = FALSE; 00172 00173 NewCellSize.cx = infoPtr->ClientSize.cx / 7; 00174 NewCellSize.cy = infoPtr->ClientSize.cy / 7; 00175 00176 if (infoPtr->CellSize.cx != NewCellSize.cx || 00177 infoPtr->CellSize.cy != NewCellSize.cy) 00178 { 00179 infoPtr->CellSize = NewCellSize; 00180 RepaintHeader = TRUE; 00181 } 00182 00183 /* Update the days layout of the current month */ 00184 ZeroMemory(infoPtr->Days, 00185 sizeof(infoPtr->Days)); 00186 00187 DayOfWeek = MonthCalDayOfWeek(infoPtr, 00188 1, 00189 infoPtr->Month, 00190 infoPtr->Year); 00191 00192 MonthLength = MonthCalMonthLength(infoPtr->Month, 00193 infoPtr->Year); 00194 00195 pDay = &infoPtr->Days[0][DayOfWeek]; 00196 pDayEnd = pDay + MonthLength; 00197 while (pDay != pDayEnd) 00198 { 00199 *(pDay++) = (BYTE)++d; 00200 } 00201 00202 /* Repaint the control */ 00203 if (RepaintHeader) 00204 { 00205 InvalidateRect(infoPtr->hSelf, 00206 NULL, 00207 TRUE); 00208 } 00209 else 00210 { 00211 RECT rcClient; 00212 00213 rcClient.left = 0; 00214 rcClient.top = infoPtr->CellSize.cy; 00215 rcClient.right = infoPtr->ClientSize.cx; 00216 rcClient.bottom = infoPtr->ClientSize.cy; 00217 00218 InvalidateRect(infoPtr->hSelf, 00219 &rcClient, 00220 TRUE); 00221 } 00222 } 00223 00224 static VOID 00225 MonthCalSetupDayTimer(IN PMONTHCALWND infoPtr) 00226 { 00227 SYSTEMTIME LocalTime = {0}; 00228 UINT uElapse; 00229 00230 /* Update the current date */ 00231 GetLocalTime(&LocalTime); 00232 00233 /* Calculate the number of remaining milliseconds until midnight */ 00234 uElapse = 1000 - (UINT)LocalTime.wMilliseconds; 00235 uElapse += (59 - (UINT)LocalTime.wSecond) * 1000; 00236 uElapse += (59 - (UINT)LocalTime.wMinute) * 60 * 1000; 00237 uElapse += (23 - (UINT)LocalTime.wHour) * 60 * 60 * 1000; 00238 00239 if (uElapse < USER_TIMER_MINIMUM || uElapse > USER_TIMER_MAXIMUM) 00240 uElapse = 1000; 00241 else 00242 uElapse += 100; /* Add a delay of 0.1 seconds */ 00243 00244 /* Setup the new timer */ 00245 if (SetTimer(infoPtr->hSelf, 00246 ID_DAYTIMER, 00247 uElapse, 00248 NULL) != 0) 00249 { 00250 infoPtr->DayTimerSet = TRUE; 00251 } 00252 } 00253 00254 static VOID 00255 MonthCalReload(IN PMONTHCALWND infoPtr) 00256 { 00257 WCHAR szBuf[64]; 00258 UINT i; 00259 00260 infoPtr->UIState = (DWORD)SendMessageW(GetAncestor(infoPtr->hSelf, 00261 GA_PARENT), 00262 WM_QUERYUISTATE, 00263 0, 00264 0); 00265 00266 /* Cache the configuration */ 00267 infoPtr->FirstDayOfWeek = MonthCalFirstDayOfWeek(); 00268 00269 infoPtr->hbHeader = GetSysColorBrush(infoPtr->Enabled ? MONTHCAL_HEADERBG : MONTHCAL_DISABLED_HEADERBG); 00270 infoPtr->hbSelection = GetSysColorBrush(infoPtr->Enabled ? MONTHCAL_SELBG : MONTHCAL_DISABLED_SELBG); 00271 00272 for (i = 0; i < 7; i++) 00273 { 00274 if (GetLocaleInfoW(LOCALE_USER_DEFAULT, 00275 LOCALE_SABBREVDAYNAME1 + 00276 ((i + infoPtr->FirstDayOfWeek) % 7), 00277 szBuf, 00278 sizeof(szBuf) / sizeof(szBuf[0])) != 0) 00279 { 00280 infoPtr->Week[i] = szBuf[0]; 00281 } 00282 } 00283 00284 /* Update the control */ 00285 MonthCalUpdate(infoPtr); 00286 } 00287 00288 static BOOL 00289 MonthCalGetDayRect(IN PMONTHCALWND infoPtr, 00290 IN WORD Day, 00291 OUT RECT *rcCell) 00292 { 00293 if (Day >= 1 && Day <= MonthCalMonthLength(infoPtr->Month, 00294 infoPtr->Year)) 00295 { 00296 WORD DayOfWeek; 00297 00298 DayOfWeek = MonthCalDayOfWeek(infoPtr, 00299 Day, 00300 infoPtr->Month, 00301 infoPtr->Year); 00302 00303 rcCell->left = DayOfWeek * infoPtr->CellSize.cx; 00304 rcCell->top = (MonthCalWeekInMonth(Day, 00305 DayOfWeek) + 1) * infoPtr->CellSize.cy; 00306 rcCell->right = rcCell->left + infoPtr->CellSize.cx; 00307 rcCell->bottom = rcCell->top + infoPtr->CellSize.cy; 00308 00309 return TRUE; 00310 } 00311 00312 return FALSE; 00313 } 00314 00315 static VOID 00316 MonthCalChange(IN PMONTHCALWND infoPtr) 00317 { 00318 infoPtr->Changed = TRUE; 00319 00320 /* Kill the day timer */ 00321 if (infoPtr->DayTimerSet) 00322 { 00323 KillTimer(infoPtr->hSelf, 00324 ID_DAYTIMER); 00325 infoPtr->DayTimerSet = FALSE; 00326 } 00327 } 00328 00329 00330 static BOOL 00331 MonthCalSetDate(IN PMONTHCALWND infoPtr, 00332 IN WORD Day, 00333 IN WORD Month, 00334 IN WORD Year) 00335 { 00336 NMMCCSELCHANGE sc; 00337 BOOL Ret = FALSE; 00338 00339 sc.OldDay = infoPtr->Day; 00340 sc.OldMonth = infoPtr->Month; 00341 sc.OldYear = infoPtr->Year; 00342 sc.NewDay = Day; 00343 sc.NewMonth = Month; 00344 sc.NewYear = Year; 00345 00346 /* Notify the parent */ 00347 if (!MonthCalNotifyControlParent(infoPtr, 00348 MCCN_SELCHANGE, 00349 &sc)) 00350 { 00351 /* Check if we actually need to update */ 00352 if (infoPtr->Month != sc.NewMonth || 00353 infoPtr->Year != sc.NewYear) 00354 { 00355 infoPtr->Day = sc.NewDay; 00356 infoPtr->Month = sc.NewMonth; 00357 infoPtr->Year = sc.NewYear; 00358 00359 MonthCalChange(infoPtr); 00360 00361 /* Repaint the entire control */ 00362 MonthCalUpdate(infoPtr); 00363 00364 Ret = TRUE; 00365 } 00366 else if (infoPtr->Day != sc.NewDay) 00367 { 00368 RECT rcUpdate; 00369 00370 infoPtr->Day = sc.NewDay; 00371 00372 MonthCalChange(infoPtr); 00373 00374 if (MonthCalGetDayRect(infoPtr, 00375 sc.OldDay, 00376 &rcUpdate)) 00377 { 00378 /* Repaint the day cells that need to be updated */ 00379 InvalidateRect(infoPtr->hSelf, 00380 &rcUpdate, 00381 TRUE); 00382 if (MonthCalGetDayRect(infoPtr, 00383 sc.NewDay, 00384 &rcUpdate)) 00385 { 00386 InvalidateRect(infoPtr->hSelf, 00387 &rcUpdate, 00388 TRUE); 00389 } 00390 } 00391 00392 Ret = TRUE; 00393 } 00394 } 00395 00396 return Ret; 00397 } 00398 00399 static VOID 00400 MonthCalSetLocalTime(IN PMONTHCALWND infoPtr, 00401 OUT SYSTEMTIME *Time) 00402 { 00403 NMMCCAUTOUPDATE au; 00404 SYSTEMTIME LocalTime = {0}; 00405 00406 GetLocalTime(&LocalTime); 00407 00408 au.SystemTime = LocalTime; 00409 if (!MonthCalNotifyControlParent(infoPtr, 00410 MCCN_AUTOUPDATE, 00411 &au)) 00412 { 00413 if (MonthCalSetDate(infoPtr, 00414 LocalTime.wDay, 00415 LocalTime.wMonth, 00416 LocalTime.wYear)) 00417 { 00418 infoPtr->Changed = FALSE; 00419 } 00420 } 00421 00422 /* Kill the day timer */ 00423 if (infoPtr->DayTimerSet) 00424 { 00425 KillTimer(infoPtr->hSelf, 00426 ID_DAYTIMER); 00427 infoPtr->DayTimerSet = FALSE; 00428 } 00429 00430 /* Setup the new day timer */ 00431 MonthCalSetupDayTimer(infoPtr); 00432 00433 if (Time != NULL) 00434 { 00435 *Time = LocalTime; 00436 } 00437 } 00438 00439 static VOID 00440 MonthCalRepaintDay(IN PMONTHCALWND infoPtr, 00441 IN WORD Day) 00442 { 00443 RECT rcCell; 00444 00445 if (MonthCalGetDayRect(infoPtr, 00446 Day, 00447 &rcCell)) 00448 { 00449 InvalidateRect(infoPtr->hSelf, 00450 &rcCell, 00451 TRUE); 00452 } 00453 } 00454 00455 static VOID 00456 MonthCalPaint(IN PMONTHCALWND infoPtr, 00457 IN HDC hDC, 00458 IN LPRECT prcUpdate) 00459 { 00460 LONG x, y; 00461 RECT rcCell; 00462 COLORREF crOldText, crOldCtrlText = CLR_INVALID; 00463 HFONT hOldFont; 00464 INT iOldBkMode; 00465 00466 #if MONTHCAL_CTRLBG != MONTHCAL_DISABLED_CTRLBG 00467 if (!infoPtr->Enabled) 00468 { 00469 FillRect(hDC, 00470 prcUpdate, 00471 GetSysColorBrush(MONTHCAL_DISABLED_CTRLBG)); 00472 } 00473 #endif 00474 00475 iOldBkMode = SetBkMode(hDC, 00476 TRANSPARENT); 00477 hOldFont = (HFONT)SelectObject(hDC, 00478 infoPtr->hFont); 00479 00480 for (y = prcUpdate->top / infoPtr->CellSize.cy; 00481 y <= prcUpdate->bottom / infoPtr->CellSize.cy && y < 7; 00482 y++) 00483 { 00484 rcCell.top = y * infoPtr->CellSize.cy; 00485 rcCell.bottom = rcCell.top + infoPtr->CellSize.cy; 00486 00487 if (y == 0) 00488 { 00489 RECT rcHeader; 00490 00491 /* Paint the header */ 00492 rcHeader.left = prcUpdate->left; 00493 rcHeader.top = rcCell.top; 00494 rcHeader.right = prcUpdate->right; 00495 rcHeader.bottom = rcCell.bottom; 00496 00497 FillRect(hDC, 00498 &rcHeader, 00499 infoPtr->hbHeader); 00500 00501 crOldText = SetTextColor(hDC, 00502 GetSysColor(infoPtr->Enabled ? MONTHCAL_HEADERFG : MONTHCAL_DISABLED_HEADERFG)); 00503 00504 for (x = prcUpdate->left / infoPtr->CellSize.cx; 00505 x <= prcUpdate->right / infoPtr->CellSize.cx && x < 7; 00506 x++) 00507 { 00508 rcCell.left = x * infoPtr->CellSize.cx; 00509 rcCell.right = rcCell.left + infoPtr->CellSize.cx; 00510 00511 /* Write the first letter of each weekday */ 00512 DrawTextW(hDC, 00513 &infoPtr->Week[x], 00514 1, 00515 &rcCell, 00516 DT_SINGLELINE | DT_NOPREFIX | DT_CENTER | DT_VCENTER); 00517 } 00518 00519 SetTextColor(hDC, 00520 crOldText); 00521 } 00522 else 00523 { 00524 if (crOldCtrlText == CLR_INVALID) 00525 { 00526 crOldCtrlText = SetTextColor(hDC, 00527 GetSysColor(infoPtr->Enabled ? MONTHCAL_CTRLFG : MONTHCAL_DISABLED_CTRLFG)); 00528 } 00529 00530 for (x = prcUpdate->left / infoPtr->CellSize.cx; 00531 x <= prcUpdate->right / infoPtr->CellSize.cx && x < 7; 00532 x++) 00533 { 00534 UINT Day = infoPtr->Days[y - 1][x]; 00535 00536 rcCell.left = x * infoPtr->CellSize.cx; 00537 rcCell.right = rcCell.left + infoPtr->CellSize.cx; 00538 00539 /* Write the day number */ 00540 if (Day != 0 && Day < 100) 00541 { 00542 WCHAR szDay[3]; 00543 INT szDayLen; 00544 RECT rcText; 00545 SIZE TextSize; 00546 00547 szDayLen = swprintf(szDay, 00548 L"%lu", 00549 Day); 00550 00551 if (GetTextExtentPoint32W(hDC, 00552 szDay, 00553 szDayLen, 00554 &TextSize)) 00555 { 00556 RECT rcHighlight = { 0, 0, 0, 0 }; 00557 00558 rcText.left = rcCell.left + (infoPtr->CellSize.cx / 2) - (TextSize.cx / 2); 00559 rcText.top = rcCell.top + (infoPtr->CellSize.cy / 2) - (TextSize.cy / 2); 00560 rcText.right = rcText.left + TextSize.cx; 00561 rcText.bottom = rcText.top + TextSize.cy; 00562 00563 if (Day == infoPtr->Day) 00564 { 00565 SIZE TextSel; 00566 00567 TextSel.cx = (infoPtr->CellSize.cx * 2) / 3; 00568 TextSel.cy = (infoPtr->CellSize.cy * 3) / 4; 00569 00570 if (TextSel.cx < rcText.right - rcText.left) 00571 TextSel.cx = rcText.right - rcText.left; 00572 if (TextSel.cy < rcText.bottom - rcText.top) 00573 TextSel.cy = rcText.bottom - rcText.top; 00574 00575 rcHighlight.left = rcCell.left + (infoPtr->CellSize.cx / 2) - (TextSel.cx / 2); 00576 rcHighlight.right = rcHighlight.left + TextSel.cx; 00577 rcHighlight.top = rcCell.top + (infoPtr->CellSize.cy / 2) - (TextSel.cy / 2); 00578 rcHighlight.bottom = rcHighlight.top + TextSel.cy; 00579 00580 InflateRect(&rcHighlight, 00581 GetSystemMetrics(SM_CXFOCUSBORDER), 00582 GetSystemMetrics(SM_CYFOCUSBORDER)); 00583 00584 if (!FillRect(hDC, 00585 &rcHighlight, 00586 infoPtr->hbSelection)) 00587 { 00588 goto FailNoHighlight; 00589 } 00590 00591 /* Highlight the selected day */ 00592 crOldText = SetTextColor(hDC, 00593 GetSysColor(infoPtr->Enabled ? MONTHCAL_SELFG : MONTHCAL_DISABLED_SELFG)); 00594 } 00595 else 00596 { 00597 FailNoHighlight: 00598 /* Don't change the text color, we're not highlighting it... */ 00599 crOldText = CLR_INVALID; 00600 } 00601 00602 TextOutW(hDC, 00603 rcText.left, 00604 rcText.top, 00605 szDay, 00606 szDayLen); 00607 00608 if (Day == infoPtr->Day && crOldText != CLR_INVALID) 00609 { 00610 if (infoPtr->HasFocus && infoPtr->Enabled && !(infoPtr->UIState & UISF_HIDEFOCUS)) 00611 { 00612 COLORREF crOldBk; 00613 00614 crOldBk = SetBkColor(hDC, 00615 GetSysColor(infoPtr->Enabled ? MONTHCAL_SELBG : MONTHCAL_DISABLED_SELBG)); 00616 00617 DrawFocusRect(hDC, 00618 &rcHighlight); 00619 00620 SetBkColor(hDC, 00621 crOldBk); 00622 } 00623 00624 SetTextColor(hDC, 00625 crOldText); 00626 } 00627 } 00628 } 00629 } 00630 } 00631 } 00632 00633 if (crOldCtrlText != CLR_INVALID) 00634 { 00635 SetTextColor(hDC, 00636 crOldCtrlText); 00637 } 00638 00639 SetBkMode(hDC, 00640 iOldBkMode); 00641 SelectObject(hDC, 00642 (HGDIOBJ)hOldFont); 00643 } 00644 00645 static HFONT 00646 MonthCalChangeFont(IN PMONTHCALWND infoPtr, 00647 IN HFONT hFont, 00648 IN BOOL Redraw) 00649 { 00650 HFONT hOldFont = infoPtr->hFont; 00651 infoPtr->hFont = hFont; 00652 00653 if (Redraw) 00654 { 00655 InvalidateRect(infoPtr->hSelf, 00656 NULL, 00657 TRUE); 00658 } 00659 00660 return hOldFont; 00661 } 00662 00663 static WORD 00664 MonthCalPtToDay(IN PMONTHCALWND infoPtr, 00665 IN INT x, 00666 IN INT y) 00667 { 00668 WORD Ret = 0; 00669 00670 if (infoPtr->CellSize.cx != 0 && infoPtr->CellSize.cy != 0 && 00671 x >= 0 && y >= 0) 00672 { 00673 x /= infoPtr->CellSize.cx; 00674 y /= infoPtr->CellSize.cy; 00675 00676 if (x < 7 && y != 0 && y < 7) 00677 { 00678 Ret = (WORD)infoPtr->Days[y - 1][x]; 00679 } 00680 } 00681 00682 return Ret; 00683 } 00684 00685 static LRESULT CALLBACK 00686 MonthCalWndProc(IN HWND hwnd, 00687 IN UINT uMsg, 00688 IN WPARAM wParam, 00689 IN LPARAM lParam) 00690 { 00691 PMONTHCALWND infoPtr; 00692 LRESULT Ret = 0; 00693 00694 infoPtr = (PMONTHCALWND)GetWindowLongPtrW(hwnd, 00695 0); 00696 00697 if (infoPtr == NULL && uMsg != WM_CREATE) 00698 { 00699 goto HandleDefaultMessage; 00700 } 00701 00702 switch (uMsg) 00703 { 00704 #if MONTHCAL_CTRLBG != MONTHCAL_DISABLED_CTRLBG 00705 case WM_ERASEBKGND: 00706 Ret = !infoPtr->Enabled; 00707 break; 00708 #endif 00709 00710 case WM_PAINT: 00711 case WM_PRINTCLIENT: 00712 { 00713 if (infoPtr->CellSize.cx != 0 && infoPtr->CellSize.cy != 0) 00714 { 00715 PAINTSTRUCT ps; 00716 HDC hDC; 00717 00718 if (wParam != 0) 00719 { 00720 if (!GetUpdateRect(hwnd, 00721 &ps.rcPaint, 00722 TRUE)) 00723 { 00724 break; 00725 } 00726 hDC = (HDC)wParam; 00727 } 00728 else 00729 { 00730 hDC = BeginPaint(hwnd, 00731 &ps); 00732 if (hDC == NULL) 00733 { 00734 break; 00735 } 00736 } 00737 00738 MonthCalPaint(infoPtr, 00739 hDC, 00740 &ps.rcPaint); 00741 00742 if (wParam == 0) 00743 { 00744 EndPaint(hwnd, 00745 &ps); 00746 } 00747 } 00748 break; 00749 } 00750 00751 case WM_LBUTTONDBLCLK: 00752 case WM_LBUTTONDOWN: 00753 { 00754 WORD SelDay; 00755 00756 SelDay = MonthCalPtToDay(infoPtr, 00757 GET_X_LPARAM(lParam), 00758 GET_Y_LPARAM(lParam)); 00759 if (SelDay != 0 && SelDay != infoPtr->Day) 00760 { 00761 MonthCalSetDate(infoPtr, 00762 SelDay, 00763 infoPtr->Month, 00764 infoPtr->Year); 00765 } 00766 00767 /* Fall through */ 00768 } 00769 00770 case WM_MBUTTONDOWN: 00771 case WM_RBUTTONDOWN: 00772 { 00773 if (!infoPtr->HasFocus) 00774 { 00775 SetFocus(hwnd); 00776 } 00777 break; 00778 } 00779 00780 case WM_KEYDOWN: 00781 { 00782 WORD NewDay = 0; 00783 00784 switch (wParam) 00785 { 00786 case VK_UP: 00787 { 00788 if (infoPtr->Day > 7) 00789 { 00790 NewDay = infoPtr->Day - 7; 00791 } 00792 break; 00793 } 00794 00795 case VK_DOWN: 00796 { 00797 if (infoPtr->Day + 7 <= MonthCalMonthLength(infoPtr->Month, 00798 infoPtr->Year)) 00799 { 00800 NewDay = infoPtr->Day + 7; 00801 } 00802 break; 00803 } 00804 00805 case VK_LEFT: 00806 { 00807 if (infoPtr->Day > 1) 00808 { 00809 NewDay = infoPtr->Day - 1; 00810 } 00811 break; 00812 } 00813 00814 case VK_RIGHT: 00815 { 00816 if (infoPtr->Day < MonthCalMonthLength(infoPtr->Month, 00817 infoPtr->Year)) 00818 { 00819 NewDay = infoPtr->Day + 1; 00820 } 00821 break; 00822 } 00823 } 00824 00825 /* Update the selection */ 00826 if (NewDay != 0) 00827 { 00828 MonthCalSetDate(infoPtr, 00829 NewDay, 00830 infoPtr->Month, 00831 infoPtr->Year); 00832 } 00833 00834 goto HandleDefaultMessage; 00835 } 00836 00837 case WM_GETDLGCODE: 00838 { 00839 INT virtKey; 00840 00841 virtKey = (lParam != 0 ? (INT)((LPMSG)lParam)->wParam : 0); 00842 switch (virtKey) 00843 { 00844 case VK_TAB: 00845 { 00846 /* Change the UI status */ 00847 SendMessageW(GetAncestor(hwnd, 00848 GA_PARENT), 00849 WM_CHANGEUISTATE, 00850 MAKEWPARAM(UIS_INITIALIZE, 00851 0), 00852 0); 00853 break; 00854 } 00855 } 00856 00857 Ret |= DLGC_WANTARROWS; 00858 break; 00859 } 00860 00861 case WM_SETFOCUS: 00862 { 00863 infoPtr->HasFocus = TRUE; 00864 MonthCalRepaintDay(infoPtr, 00865 infoPtr->Day); 00866 break; 00867 } 00868 00869 case WM_KILLFOCUS: 00870 { 00871 infoPtr->HasFocus = FALSE; 00872 MonthCalRepaintDay(infoPtr, 00873 infoPtr->Day); 00874 break; 00875 } 00876 00877 case WM_UPDATEUISTATE: 00878 { 00879 DWORD OldUIState; 00880 00881 Ret = DefWindowProcW(hwnd, 00882 uMsg, 00883 wParam, 00884 lParam); 00885 00886 OldUIState = infoPtr->UIState; 00887 switch (LOWORD(wParam)) 00888 { 00889 case UIS_SET: 00890 infoPtr->UIState |= HIWORD(wParam); 00891 break; 00892 00893 case UIS_CLEAR: 00894 infoPtr->UIState &= ~HIWORD(wParam); 00895 break; 00896 } 00897 00898 if (infoPtr->UIState != OldUIState) 00899 { 00900 MonthCalRepaintDay(infoPtr, 00901 infoPtr->Day); 00902 } 00903 break; 00904 } 00905 00906 case MCCM_SETDATE: 00907 { 00908 WORD Day, Month, Year, DaysCount; 00909 00910 Day = LOWORD(wParam); 00911 Month = HIWORD(wParam); 00912 Year = LOWORD(lParam); 00913 00914 if (Day == (WORD)-1) 00915 Day = infoPtr->Day; 00916 if (Month == (WORD)-1) 00917 Month = infoPtr->Month; 00918 if (Year == (WORD)-1) 00919 Year = infoPtr->Year; 00920 00921 DaysCount = MonthCalMonthLength(Month, 00922 Year); 00923 if (Day > DaysCount) 00924 Day = DaysCount; 00925 00926 if (MonthCalValidDate(Day, 00927 Month, 00928 Year)) 00929 { 00930 if (Day != infoPtr->Day || 00931 Month != infoPtr->Month || 00932 Year != infoPtr->Year) 00933 { 00934 Ret = MonthCalSetDate(infoPtr, 00935 Day, 00936 Month, 00937 Year); 00938 } 00939 } 00940 break; 00941 } 00942 00943 case MCCM_GETDATE: 00944 { 00945 LPSYSTEMTIME lpSystemTime = (LPSYSTEMTIME)wParam; 00946 00947 lpSystemTime->wYear = infoPtr->Year; 00948 lpSystemTime->wMonth = infoPtr->Month; 00949 lpSystemTime->wDay = infoPtr->Day; 00950 00951 Ret = TRUE; 00952 break; 00953 } 00954 00955 case MCCM_RESET: 00956 { 00957 MonthCalSetLocalTime(infoPtr, 00958 NULL); 00959 Ret = TRUE; 00960 break; 00961 } 00962 00963 case MCCM_CHANGED: 00964 { 00965 Ret = infoPtr->Changed; 00966 break; 00967 } 00968 00969 case WM_TIMER: 00970 { 00971 switch (wParam) 00972 { 00973 case ID_DAYTIMER: 00974 { 00975 /* Kill the timer */ 00976 KillTimer(hwnd, 00977 ID_DAYTIMER); 00978 infoPtr->DayTimerSet = FALSE; 00979 00980 if (!infoPtr->Changed) 00981 { 00982 /* Update the system time and setup the new day timer */ 00983 MonthCalSetLocalTime(infoPtr, 00984 NULL); 00985 00986 /* Update the control */ 00987 MonthCalUpdate(infoPtr); 00988 } 00989 break; 00990 } 00991 } 00992 break; 00993 } 00994 00995 case WM_SETFONT: 00996 { 00997 Ret = (LRESULT)MonthCalChangeFont(infoPtr, 00998 (HFONT)wParam, 00999 (BOOL)LOWORD(lParam)); 01000 break; 01001 } 01002 01003 case WM_SIZE: 01004 { 01005 infoPtr->ClientSize.cx = LOWORD(lParam); 01006 infoPtr->ClientSize.cy = HIWORD(lParam); 01007 infoPtr->CellSize.cx = infoPtr->ClientSize.cx / 7; 01008 infoPtr->CellSize.cy = infoPtr->ClientSize.cy / 7; 01009 01010 /* Repaint the control */ 01011 InvalidateRect(hwnd, 01012 NULL, 01013 TRUE); 01014 break; 01015 } 01016 01017 case WM_GETFONT: 01018 { 01019 Ret = (LRESULT)infoPtr->hFont; 01020 break; 01021 } 01022 01023 case WM_ENABLE: 01024 { 01025 infoPtr->Enabled = ((BOOL)wParam != FALSE); 01026 MonthCalReload(infoPtr); 01027 break; 01028 } 01029 01030 case WM_STYLECHANGED: 01031 { 01032 if (wParam == GWL_STYLE) 01033 { 01034 unsigned int OldEnabled = infoPtr->Enabled; 01035 infoPtr->Enabled = !(((LPSTYLESTRUCT)lParam)->styleNew & WS_DISABLED); 01036 01037 if (OldEnabled != infoPtr->Enabled) 01038 { 01039 MonthCalReload(infoPtr); 01040 } 01041 } 01042 break; 01043 } 01044 01045 case WM_CREATE: 01046 { 01047 infoPtr = (MONTHCALWND*) HeapAlloc(GetProcessHeap(), 01048 0, 01049 sizeof(MONTHCALWND)); 01050 if (infoPtr == NULL) 01051 { 01052 Ret = (LRESULT)-1; 01053 break; 01054 } 01055 01056 SetWindowLongPtrW(hwnd, 01057 0, 01058 (LONG_PTR)infoPtr); 01059 01060 ZeroMemory(infoPtr, 01061 sizeof(MONTHCALWND)); 01062 01063 infoPtr->hSelf = hwnd; 01064 infoPtr->hNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; 01065 infoPtr->Enabled = !(((LPCREATESTRUCTW)lParam)->style & WS_DISABLED); 01066 01067 MonthCalSetLocalTime(infoPtr, 01068 NULL); 01069 01070 MonthCalReload(infoPtr); 01071 break; 01072 } 01073 01074 case WM_DESTROY: 01075 { 01076 HeapFree(GetProcessHeap(), 01077 0, 01078 infoPtr); 01079 SetWindowLongPtrW(hwnd, 01080 0, 01081 (DWORD_PTR)NULL); 01082 break; 01083 } 01084 01085 default: 01086 { 01087 HandleDefaultMessage: 01088 Ret = DefWindowProcW(hwnd, 01089 uMsg, 01090 wParam, 01091 lParam); 01092 break; 01093 } 01094 } 01095 01096 return Ret; 01097 } 01098 01099 BOOL 01100 RegisterMonthCalControl(IN HINSTANCE hInstance) 01101 { 01102 WNDCLASSW wc = {0}; 01103 01104 wc.style = CS_DBLCLKS; 01105 wc.lpfnWndProc = MonthCalWndProc; 01106 wc.cbWndExtra = sizeof(PMONTHCALWND); 01107 wc.hInstance = hInstance; 01108 wc.hCursor = LoadCursorW(NULL, 01109 (LPWSTR)IDC_ARROW); 01110 wc.hbrBackground = (HBRUSH)(MONTHCAL_CTRLBG + 1); 01111 wc.lpszClassName = szMonthCalWndClass; 01112 01113 return RegisterClassW(&wc) != 0; 01114 } 01115 01116 VOID 01117 UnregisterMonthCalControl(IN HINSTANCE hInstance) 01118 { 01119 UnregisterClassW(szMonthCalWndClass, 01120 hInstance); 01121 } Generated on Sat May 26 2012 04:19:47 for ReactOS by
1.7.6.1
|