ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

monthcal.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.