ReactOS  0.4.15-dev-3163-gf17c2c0
monthcal.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Timedate Control Panel
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: dll/cpl/timedate/monthcal.c
5  * PURPOSE: Calander implementation
6  * COPYRIGHT: Copyright 2006 Thomas Weidenmueller <w3seek@reactos.com>
7  *
8  */
9 
10 #include "timedate.h"
11 
12 #include <windowsx.h>
13 
14 static const WCHAR szMonthCalWndClass[] = L"MonthCalWnd";
15 
16 #define MONTHCAL_HEADERBG COLOR_INACTIVECAPTION
17 #define MONTHCAL_HEADERFG COLOR_INACTIVECAPTIONTEXT
18 #define MONTHCAL_CTRLBG COLOR_WINDOW
19 #define MONTHCAL_CTRLFG COLOR_WINDOWTEXT
20 #define MONTHCAL_SELBG COLOR_ACTIVECAPTION
21 #define MONTHCAL_SELFG COLOR_CAPTIONTEXT
22 #define MONTHCAL_DISABLED_HEADERBG COLOR_INACTIVECAPTION
23 #define MONTHCAL_DISABLED_HEADERFG COLOR_INACTIVECAPTIONTEXT
24 #define MONTHCAL_DISABLED_CTRLBG COLOR_WINDOW
25 #define MONTHCAL_DISABLED_CTRLFG COLOR_WINDOWTEXT
26 #define MONTHCAL_DISABLED_SELBG COLOR_INACTIVECAPTION
27 #define MONTHCAL_DISABLED_SELFG COLOR_INACTIVECAPTIONTEXT
28 
29 #define ID_DAYTIMER 1
30 
31 typedef struct _MONTHCALWND
32 {
39  BYTE Days[6][7];
40  WCHAR Week[7];
43 
45  HBRUSH hbHeader;
46  HBRUSH hbSelection;
47 
54 
55 static LRESULT
57  IN UINT code,
58  IN OUT PVOID data)
59 {
60  LRESULT Ret = 0;
61 
62  if (infoPtr->hNotify != NULL)
63  {
64  LPNMHDR pnmh = (LPNMHDR)data;
65 
66  pnmh->hwndFrom = infoPtr->hSelf;
67  pnmh->idFrom = GetWindowLongPtrW(infoPtr->hSelf,
68  GWLP_ID);
69  pnmh->code = code;
70 
71  Ret = SendMessageW(infoPtr->hNotify,
72  WM_NOTIFY,
73  (WPARAM)pnmh->idFrom,
74  (LPARAM)pnmh);
75  }
76 
77  return Ret;
78 }
79 
80 /*
81  * For the year range 1..9999
82  * return 1 if is leap year otherwise 0
83  */
84 static WORD LeapYear(IN WORD Year)
85 {
86  return
87 #ifdef WITH_1752
88  (Year <= 1752) ? !(Year % 4) :
89 #endif
90  !(Year % 4) && ((Year % 100) || !(Year % 400));
91 }
92 
93 static WORD
95  IN WORD Year)
96 {
97  const BYTE MonthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
98 
99  if(Month == 2)
100  return MonthDays[Month - 1] + LeapYear(Year);
101  else
102  {
103 #ifdef WITH_1752
104  if ((Year == 1752) && (Month == 9))
105  return 19; // Special case: September 1752 has no 3rd-13th
106  else
107 #endif
108  return MonthDays[Month - 1];
109  }
110 }
111 
112 static WORD
114  IN WORD DayOfWeek)
115 {
116  return (Day - DayOfWeek + 5) / 7;
117 }
118 
119 static WORD
121  IN WORD Day,
122  IN WORD Month,
123  IN WORD Year)
124 {
125  const BYTE DayOfWeek[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
126  WORD Ret;
127 
128  Year -= (Month < 3);
129  Ret = (Year + (Year / 4) - (Year / 100) + (Year / 400) + DayOfWeek[Month - 1] + Day + 6) % 7;
130 
131  return (7 + Ret - infoPtr->FirstDayOfWeek) % 7;
132 }
133 
134 static WORD
136 {
137  WCHAR szBuf[2] = {0};
138  WORD Ret = 0;
139 
142  szBuf,
143  sizeof(szBuf) / sizeof(szBuf[0])) != 0)
144  {
145  Ret = (WORD)(szBuf[0] - TEXT('0'));
146  }
147 
148  return Ret;
149 }
150 
151 static BOOL
153  IN WORD Month,
154  IN WORD Year)
155 {
156  if (Month < 1 || Month > 12 ||
157  Day == 0 || Day > MonthCalMonthLength(Month,
158  Year) ||
159  Year < 1899 || Year > 9999)
160  {
161  return FALSE;
162  }
163 
164  return TRUE;
165 }
166 
167 static VOID
169 {
170  PBYTE pDay, pDayEnd;
171  WORD DayOfWeek, MonthLength, d = 0;
172  SIZE NewCellSize;
173  BOOL RepaintHeader = FALSE;
174 
175  NewCellSize.cx = infoPtr->ClientSize.cx / 7;
176  NewCellSize.cy = infoPtr->ClientSize.cy / 7;
177 
178  if (infoPtr->CellSize.cx != NewCellSize.cx ||
179  infoPtr->CellSize.cy != NewCellSize.cy)
180  {
181  infoPtr->CellSize = NewCellSize;
182  RepaintHeader = TRUE;
183  }
184 
185  /* Update the days layout of the current month */
186  ZeroMemory(infoPtr->Days,
187  sizeof(infoPtr->Days));
188 
189  DayOfWeek = MonthCalDayOfWeek(infoPtr,
190  1,
191  infoPtr->Month,
192  infoPtr->Year);
193 
194  MonthLength = MonthCalMonthLength(infoPtr->Month,
195  infoPtr->Year);
196 
197  pDay = &infoPtr->Days[0][DayOfWeek];
198  pDayEnd = pDay + MonthLength;
199  while (pDay != pDayEnd)
200  {
201  *(pDay++) = (BYTE)++d;
202  }
203 
204  /* Repaint the control */
205  if (RepaintHeader)
206  {
207  InvalidateRect(infoPtr->hSelf,
208  NULL,
209  TRUE);
210  }
211  else
212  {
213  RECT rcClient;
214 
215  rcClient.left = 0;
216  rcClient.top = infoPtr->CellSize.cy;
217  rcClient.right = infoPtr->ClientSize.cx;
218  rcClient.bottom = infoPtr->ClientSize.cy;
219 
220  InvalidateRect(infoPtr->hSelf,
221  &rcClient,
222  TRUE);
223  }
224 }
225 
226 static VOID
228 {
229  SYSTEMTIME LocalTime = {0};
230  UINT uElapse;
231 
232  /* Update the current date */
233  GetLocalTime(&LocalTime);
234 
235  /* Calculate the number of remaining milliseconds until midnight */
236  uElapse = 1000 - (UINT)LocalTime.wMilliseconds;
237  uElapse += (59 - (UINT)LocalTime.wSecond) * 1000;
238  uElapse += (59 - (UINT)LocalTime.wMinute) * 60 * 1000;
239  uElapse += (23 - (UINT)LocalTime.wHour) * 60 * 60 * 1000;
240 
241  /* Setup the new timer */
242  if (SetTimer(infoPtr->hSelf,
243  ID_DAYTIMER,
244  uElapse,
245  NULL) != 0)
246  {
247  infoPtr->DayTimerSet = TRUE;
248  }
249 }
250 
251 static VOID
253 {
254  WCHAR szBuf[64];
255  UINT i;
256 
257  infoPtr->UIState = (DWORD)SendMessageW(GetAncestor(infoPtr->hSelf,
258  GA_PARENT),
259  WM_QUERYUISTATE,
260  0,
261  0);
262 
263  /* Cache the configuration */
264  infoPtr->FirstDayOfWeek = MonthCalFirstDayOfWeek();
265 
266  infoPtr->hbHeader = GetSysColorBrush(infoPtr->Enabled ? MONTHCAL_HEADERBG : MONTHCAL_DISABLED_HEADERBG);
267  infoPtr->hbSelection = GetSysColorBrush(infoPtr->Enabled ? MONTHCAL_SELBG : MONTHCAL_DISABLED_SELBG);
268 
269  for (i = 0; i < 7; i++)
270  {
273  ((i + infoPtr->FirstDayOfWeek) % 7),
274  szBuf,
275  sizeof(szBuf) / sizeof(szBuf[0])) != 0)
276  {
277  infoPtr->Week[i] = szBuf[0];
278  }
279  }
280 
281  /* Update the control */
282  MonthCalUpdate(infoPtr);
283 }
284 
285 static BOOL
287  IN WORD Day,
288  OUT RECT *rcCell)
289 {
290  if (Day >= 1 && Day <= MonthCalMonthLength(infoPtr->Month,
291  infoPtr->Year))
292  {
293  WORD DayOfWeek;
294 
295  DayOfWeek = MonthCalDayOfWeek(infoPtr,
296  Day,
297  infoPtr->Month,
298  infoPtr->Year);
299 
300  rcCell->left = DayOfWeek * infoPtr->CellSize.cx;
301  rcCell->top = (MonthCalWeekInMonth(Day,
302  DayOfWeek) + 1) * infoPtr->CellSize.cy;
303  rcCell->right = rcCell->left + infoPtr->CellSize.cx;
304  rcCell->bottom = rcCell->top + infoPtr->CellSize.cy;
305 
306  return TRUE;
307  }
308 
309  return FALSE;
310 }
311 
312 static VOID
314 {
315  infoPtr->Changed = TRUE;
316 
317  /* Kill the day timer */
318  if (infoPtr->DayTimerSet)
319  {
320  KillTimer(infoPtr->hSelf,
321  ID_DAYTIMER);
322  infoPtr->DayTimerSet = FALSE;
323  }
324 }
325 
326 
327 static BOOL
329  IN WORD Day,
330  IN WORD Month,
331  IN WORD Year)
332 {
333  NMMCCSELCHANGE sc;
334  BOOL Ret = FALSE;
335 
336  sc.OldDay = infoPtr->Day;
337  sc.OldMonth = infoPtr->Month;
338  sc.OldYear = infoPtr->Year;
339  sc.NewDay = Day;
340  sc.NewMonth = Month;
341  sc.NewYear = Year;
342 
343  /* Notify the parent */
344  if (!MonthCalNotifyControlParent(infoPtr,
346  &sc))
347  {
348  /* Check if we actually need to update */
349  if (infoPtr->Month != sc.NewMonth ||
350  infoPtr->Year != sc.NewYear)
351  {
352  infoPtr->Day = sc.NewDay;
353  infoPtr->Month = sc.NewMonth;
354  infoPtr->Year = sc.NewYear;
355 
356  MonthCalChange(infoPtr);
357 
358  /* Repaint the entire control */
359  MonthCalUpdate(infoPtr);
360 
361  Ret = TRUE;
362  }
363  else if (infoPtr->Day != sc.NewDay)
364  {
365  RECT rcUpdate;
366 
367  infoPtr->Day = sc.NewDay;
368 
369  MonthCalChange(infoPtr);
370 
371  if (MonthCalGetDayRect(infoPtr,
372  sc.OldDay,
373  &rcUpdate))
374  {
375  /* Repaint the day cells that need to be updated */
376  InvalidateRect(infoPtr->hSelf,
377  &rcUpdate,
378  TRUE);
379  if (MonthCalGetDayRect(infoPtr,
380  sc.NewDay,
381  &rcUpdate))
382  {
383  InvalidateRect(infoPtr->hSelf,
384  &rcUpdate,
385  TRUE);
386  }
387  }
388 
389  Ret = TRUE;
390  }
391  }
392 
393  return Ret;
394 }
395 
396 static VOID
399 {
400  NMMCCAUTOUPDATE au;
401  SYSTEMTIME LocalTime = {0};
402 
403  GetLocalTime(&LocalTime);
404 
405  au.SystemTime = LocalTime;
406  if (!MonthCalNotifyControlParent(infoPtr,
408  &au))
409  {
410  if (MonthCalSetDate(infoPtr,
411  LocalTime.wDay,
412  LocalTime.wMonth,
413  LocalTime.wYear))
414  {
415  infoPtr->Changed = FALSE;
416  }
417  }
418 
419  /* Kill the day timer */
420  if (infoPtr->DayTimerSet)
421  {
422  KillTimer(infoPtr->hSelf,
423  ID_DAYTIMER);
424  infoPtr->DayTimerSet = FALSE;
425  }
426 
427  /* Setup the new day timer */
428  MonthCalSetupDayTimer(infoPtr);
429 
430  if (Time != NULL)
431  {
432  *Time = LocalTime;
433  }
434 }
435 
436 static VOID
438  IN WORD Day)
439 {
440  RECT rcCell;
441 
442  if (MonthCalGetDayRect(infoPtr,
443  Day,
444  &rcCell))
445  {
446  InvalidateRect(infoPtr->hSelf,
447  &rcCell,
448  TRUE);
449  }
450 }
451 
452 static VOID
454  IN HDC hDC,
455  IN LPRECT prcUpdate)
456 {
457  LONG x, y;
458  RECT rcCell;
459  COLORREF crOldText, crOldCtrlText = CLR_INVALID;
460  HFONT hOldFont;
461  INT iOldBkMode;
462 
463 #if MONTHCAL_CTRLBG != MONTHCAL_DISABLED_CTRLBG
464  if (!infoPtr->Enabled)
465  {
466  FillRect(hDC,
467  prcUpdate,
469  }
470 #endif
471 
472  iOldBkMode = SetBkMode(hDC,
473  TRANSPARENT);
474  hOldFont = (HFONT)SelectObject(hDC,
475  infoPtr->hFont);
476 
477  for (y = prcUpdate->top / infoPtr->CellSize.cy;
478  y <= prcUpdate->bottom / infoPtr->CellSize.cy && y < 7;
479  y++)
480  {
481  rcCell.top = y * infoPtr->CellSize.cy;
482  rcCell.bottom = rcCell.top + infoPtr->CellSize.cy;
483 
484  if (y == 0)
485  {
486  RECT rcHeader;
487 
488  /* Paint the header */
489  rcHeader.left = prcUpdate->left;
490  rcHeader.top = rcCell.top;
491  rcHeader.right = prcUpdate->right;
492  rcHeader.bottom = rcCell.bottom;
493 
494  FillRect(hDC,
495  &rcHeader,
496  infoPtr->hbHeader);
497 
498  crOldText = SetTextColor(hDC,
500 
501  for (x = prcUpdate->left / infoPtr->CellSize.cx;
502  x <= prcUpdate->right / infoPtr->CellSize.cx && x < 7;
503  x++)
504  {
505  rcCell.left = x * infoPtr->CellSize.cx;
506  rcCell.right = rcCell.left + infoPtr->CellSize.cx;
507 
508  /* Write the first letter of each weekday */
509  DrawTextW(hDC,
510  &infoPtr->Week[x],
511  1,
512  &rcCell,
514  }
515 
517  crOldText);
518  }
519  else
520  {
521  if (crOldCtrlText == CLR_INVALID)
522  {
523  crOldCtrlText = SetTextColor(hDC,
525  }
526 
527  for (x = prcUpdate->left / infoPtr->CellSize.cx;
528  x <= prcUpdate->right / infoPtr->CellSize.cx && x < 7;
529  x++)
530  {
531  UINT Day = infoPtr->Days[y - 1][x];
532 
533  rcCell.left = x * infoPtr->CellSize.cx;
534  rcCell.right = rcCell.left + infoPtr->CellSize.cx;
535 
536  /* Write the day number */
537  if (Day != 0 && Day < 100)
538  {
539  WCHAR szDay[3];
540  INT szDayLen;
541  RECT rcText;
542  SIZE TextSize;
543 
544  szDayLen = swprintf(szDay,
545  L"%lu",
546  Day);
547 
549  szDay,
550  szDayLen,
551  &TextSize))
552  {
553  RECT rcHighlight = { 0, 0, 0, 0 };
554 
555  rcText.left = rcCell.left + (infoPtr->CellSize.cx / 2) - (TextSize.cx / 2);
556  rcText.top = rcCell.top + (infoPtr->CellSize.cy / 2) - (TextSize.cy / 2);
557  rcText.right = rcText.left + TextSize.cx;
558  rcText.bottom = rcText.top + TextSize.cy;
559 
560  if (Day == infoPtr->Day)
561  {
562  SIZE TextSel;
563 
564  TextSel.cx = (infoPtr->CellSize.cx * 2) / 3;
565  TextSel.cy = (infoPtr->CellSize.cy * 3) / 4;
566 
567  if (TextSel.cx < rcText.right - rcText.left)
568  TextSel.cx = rcText.right - rcText.left;
569  if (TextSel.cy < rcText.bottom - rcText.top)
570  TextSel.cy = rcText.bottom - rcText.top;
571 
572  rcHighlight.left = rcCell.left + (infoPtr->CellSize.cx / 2) - (TextSel.cx / 2);
573  rcHighlight.right = rcHighlight.left + TextSel.cx;
574  rcHighlight.top = rcCell.top + (infoPtr->CellSize.cy / 2) - (TextSel.cy / 2);
575  rcHighlight.bottom = rcHighlight.top + TextSel.cy;
576 
577  InflateRect(&rcHighlight,
578  GetSystemMetrics(SM_CXFOCUSBORDER),
579  GetSystemMetrics(SM_CYFOCUSBORDER));
580 
581  if (!FillRect(hDC,
582  &rcHighlight,
583  infoPtr->hbSelection))
584  {
585  goto FailNoHighlight;
586  }
587 
588  /* Highlight the selected day */
589  crOldText = SetTextColor(hDC,
590  GetSysColor(infoPtr->Enabled ? MONTHCAL_SELFG : MONTHCAL_DISABLED_SELFG));
591  }
592  else
593  {
594 FailNoHighlight:
595  /* Don't change the text color, we're not highlighting it... */
596  crOldText = CLR_INVALID;
597  }
598 
599  TextOutW(hDC,
600  rcText.left,
601  rcText.top,
602  szDay,
603  szDayLen);
604 
605  if (Day == infoPtr->Day && crOldText != CLR_INVALID)
606  {
607  if (infoPtr->HasFocus && infoPtr->Enabled && !(infoPtr->UIState & UISF_HIDEFOCUS))
608  {
609  COLORREF crOldBk;
610 
611  crOldBk = SetBkColor(hDC,
612  GetSysColor(infoPtr->Enabled ? MONTHCAL_SELBG : MONTHCAL_DISABLED_SELBG));
613 
615  &rcHighlight);
616 
617  SetBkColor(hDC,
618  crOldBk);
619  }
620 
622  crOldText);
623  }
624  }
625  }
626  }
627  }
628  }
629 
630  if (crOldCtrlText != CLR_INVALID)
631  {
633  crOldCtrlText);
634  }
635 
636  SetBkMode(hDC,
637  iOldBkMode);
639  (HGDIOBJ)hOldFont);
640 }
641 
642 static HFONT
644  IN HFONT hFont,
645  IN BOOL Redraw)
646 {
647  HFONT hOldFont = infoPtr->hFont;
648  infoPtr->hFont = hFont;
649 
650  if (Redraw)
651  {
652  InvalidateRect(infoPtr->hSelf,
653  NULL,
654  TRUE);
655  }
656 
657  return hOldFont;
658 }
659 
660 static WORD
662  IN INT x,
663  IN INT y)
664 {
665  WORD Ret = 0;
666 
667  if (infoPtr->CellSize.cx != 0 && infoPtr->CellSize.cy != 0 &&
668  x >= 0 && y >= 0)
669  {
670  x /= infoPtr->CellSize.cx;
671  y /= infoPtr->CellSize.cy;
672 
673  if (x < 7 && y != 0 && y < 7)
674  {
675  Ret = (WORD)infoPtr->Days[y - 1][x];
676  }
677  }
678 
679  return Ret;
680 }
681 
682 static LRESULT CALLBACK
684  IN UINT uMsg,
685  IN WPARAM wParam,
686  IN LPARAM lParam)
687 {
688  PMONTHCALWND infoPtr;
689  LRESULT Ret = 0;
690 
692  0);
693 
694  if (infoPtr == NULL && uMsg != WM_CREATE)
695  {
696  goto HandleDefaultMessage;
697  }
698 
699  switch (uMsg)
700  {
701 #if MONTHCAL_CTRLBG != MONTHCAL_DISABLED_CTRLBG
702  case WM_ERASEBKGND:
703  Ret = !infoPtr->Enabled;
704  break;
705 #endif
706 
707  case WM_PAINT:
708  case WM_PRINTCLIENT:
709  {
710  if (infoPtr->CellSize.cx != 0 && infoPtr->CellSize.cy != 0)
711  {
712  PAINTSTRUCT ps;
713  HDC hDC;
714 
715  if (wParam != 0)
716  {
717  if (!GetUpdateRect(hwnd,
718  &ps.rcPaint,
719  TRUE))
720  {
721  break;
722  }
723  hDC = (HDC)wParam;
724  }
725  else
726  {
727  hDC = BeginPaint(hwnd,
728  &ps);
729  if (hDC == NULL)
730  {
731  break;
732  }
733  }
734 
735  MonthCalPaint(infoPtr,
736  hDC,
737  &ps.rcPaint);
738 
739  if (wParam == 0)
740  {
741  EndPaint(hwnd,
742  &ps);
743  }
744  }
745  break;
746  }
747 
748  case WM_LBUTTONDBLCLK:
749  case WM_LBUTTONDOWN:
750  {
751  WORD SelDay;
752 
753  SelDay = MonthCalPtToDay(infoPtr,
756  if (SelDay != 0 && SelDay != infoPtr->Day)
757  {
758  MonthCalSetDate(infoPtr,
759  SelDay,
760  infoPtr->Month,
761  infoPtr->Year);
762  }
763 
764  /* Fall through */
765  }
766 
767  case WM_MBUTTONDOWN:
768  case WM_RBUTTONDOWN:
769  {
770  if (!infoPtr->HasFocus)
771  {
772  SetFocus(hwnd);
773  }
774  break;
775  }
776 
777  case WM_KEYDOWN:
778  {
779  WORD NewDay = 0;
780 
781  switch (wParam)
782  {
783  case VK_UP:
784  {
785  if (infoPtr->Day > 7)
786  {
787  NewDay = infoPtr->Day - 7;
788  }
789  break;
790  }
791 
792  case VK_DOWN:
793  {
794  if (infoPtr->Day + 7 <= MonthCalMonthLength(infoPtr->Month,
795  infoPtr->Year))
796  {
797  NewDay = infoPtr->Day + 7;
798  }
799  break;
800  }
801 
802  case VK_LEFT:
803  {
804  if (infoPtr->Day > 1)
805  {
806  NewDay = infoPtr->Day - 1;
807  }
808  break;
809  }
810 
811  case VK_RIGHT:
812  {
813  if (infoPtr->Day < MonthCalMonthLength(infoPtr->Month,
814  infoPtr->Year))
815  {
816  NewDay = infoPtr->Day + 1;
817  }
818  break;
819  }
820  }
821 
822  /* Update the selection */
823  if (NewDay != 0)
824  {
825  MonthCalSetDate(infoPtr,
826  NewDay,
827  infoPtr->Month,
828  infoPtr->Year);
829  }
830 
831  goto HandleDefaultMessage;
832  }
833 
834  case WM_GETDLGCODE:
835  {
836  INT virtKey;
837 
838  virtKey = (lParam != 0 ? (INT)((LPMSG)lParam)->wParam : 0);
839  switch (virtKey)
840  {
841  case VK_TAB:
842  {
843  /* Change the UI status */
845  GA_PARENT),
846  WM_CHANGEUISTATE,
847  MAKEWPARAM(UIS_INITIALIZE,
848  0),
849  0);
850  break;
851  }
852  }
853 
854  Ret |= DLGC_WANTARROWS;
855  break;
856  }
857 
858  case WM_SETFOCUS:
859  {
860  infoPtr->HasFocus = TRUE;
861  MonthCalRepaintDay(infoPtr,
862  infoPtr->Day);
863  break;
864  }
865 
866  case WM_KILLFOCUS:
867  {
868  infoPtr->HasFocus = FALSE;
869  MonthCalRepaintDay(infoPtr,
870  infoPtr->Day);
871  break;
872  }
873 
874  case WM_UPDATEUISTATE:
875  {
876  DWORD OldUIState;
877 
878  Ret = DefWindowProcW(hwnd,
879  uMsg,
880  wParam,
881  lParam);
882 
883  OldUIState = infoPtr->UIState;
884  switch (LOWORD(wParam))
885  {
886  case UIS_SET:
887  infoPtr->UIState |= HIWORD(wParam);
888  break;
889 
890  case UIS_CLEAR:
891  infoPtr->UIState &= ~HIWORD(wParam);
892  break;
893  }
894 
895  if (infoPtr->UIState != OldUIState)
896  {
897  MonthCalRepaintDay(infoPtr,
898  infoPtr->Day);
899  }
900  break;
901  }
902 
903  case MCCM_SETDATE:
904  {
905  WORD Day, Month, Year, DaysCount;
906 
907  Day = LOWORD(wParam);
908  Month = HIWORD(wParam);
909  Year = LOWORD(lParam);
910 
911  if (Day == (WORD)-1)
912  Day = infoPtr->Day;
913  if (Month == (WORD)-1)
914  Month = infoPtr->Month;
915  if (Year == (WORD)-1)
916  Year = infoPtr->Year;
917 
918  DaysCount = MonthCalMonthLength(Month,
919  Year);
920  if (Day > DaysCount)
921  Day = DaysCount;
922 
923  if (MonthCalValidDate(Day,
924  Month,
925  Year))
926  {
927  if (Day != infoPtr->Day ||
928  Month != infoPtr->Month ||
929  Year != infoPtr->Year)
930  {
931  Ret = MonthCalSetDate(infoPtr,
932  Day,
933  Month,
934  Year);
935  }
936  }
937  break;
938  }
939 
940  case MCCM_GETDATE:
941  {
942  LPSYSTEMTIME lpSystemTime = (LPSYSTEMTIME)wParam;
943 
944  lpSystemTime->wYear = infoPtr->Year;
945  lpSystemTime->wMonth = infoPtr->Month;
946  lpSystemTime->wDay = infoPtr->Day;
947 
948  Ret = TRUE;
949  break;
950  }
951 
952  case MCCM_RESET:
953  {
954  MonthCalSetLocalTime(infoPtr,
955  NULL);
956  Ret = TRUE;
957  break;
958  }
959 
960  case MCCM_CHANGED:
961  {
962  Ret = infoPtr->Changed;
963  break;
964  }
965 
966  case WM_TIMER:
967  {
968  switch (wParam)
969  {
970  case ID_DAYTIMER:
971  {
972  /* Kill the timer */
973  KillTimer(hwnd,
974  ID_DAYTIMER);
975  infoPtr->DayTimerSet = FALSE;
976 
977  if (!infoPtr->Changed)
978  {
979  /* Update the system time and setup the new day timer */
980  MonthCalSetLocalTime(infoPtr,
981  NULL);
982 
983  /* Update the control */
984  MonthCalUpdate(infoPtr);
985  }
986  break;
987  }
988  }
989  break;
990  }
991 
992  case WM_SETFONT:
993  {
994  Ret = (LRESULT)MonthCalChangeFont(infoPtr,
995  (HFONT)wParam,
996  (BOOL)LOWORD(lParam));
997  break;
998  }
999 
1000  case WM_SIZE:
1001  {
1002  infoPtr->ClientSize.cx = LOWORD(lParam);
1003  infoPtr->ClientSize.cy = HIWORD(lParam);
1004  infoPtr->CellSize.cx = infoPtr->ClientSize.cx / 7;
1005  infoPtr->CellSize.cy = infoPtr->ClientSize.cy / 7;
1006 
1007  /* Repaint the control */
1009  NULL,
1010  TRUE);
1011  break;
1012  }
1013 
1014  case WM_GETFONT:
1015  {
1016  Ret = (LRESULT)infoPtr->hFont;
1017  break;
1018  }
1019 
1020  case WM_ENABLE:
1021  {
1022  infoPtr->Enabled = ((BOOL)wParam != FALSE);
1023  MonthCalReload(infoPtr);
1024  break;
1025  }
1026 
1027  case WM_STYLECHANGED:
1028  {
1029  if (wParam == GWL_STYLE)
1030  {
1031  unsigned int OldEnabled = infoPtr->Enabled;
1032  infoPtr->Enabled = !(((LPSTYLESTRUCT)lParam)->styleNew & WS_DISABLED);
1033 
1034  if (OldEnabled != infoPtr->Enabled)
1035  {
1036  MonthCalReload(infoPtr);
1037  }
1038  }
1039  break;
1040  }
1041 
1042  case WM_CREATE:
1043  {
1044  infoPtr = (MONTHCALWND*) HeapAlloc(GetProcessHeap(),
1045  0,
1046  sizeof(MONTHCALWND));
1047  if (infoPtr == NULL)
1048  {
1049  Ret = (LRESULT)-1;
1050  break;
1051  }
1052 
1054  0,
1055  (LONG_PTR)infoPtr);
1056 
1057  ZeroMemory(infoPtr,
1058  sizeof(MONTHCALWND));
1059 
1060  infoPtr->hSelf = hwnd;
1061  infoPtr->hNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
1062  infoPtr->Enabled = !(((LPCREATESTRUCTW)lParam)->style & WS_DISABLED);
1063 
1064  MonthCalSetLocalTime(infoPtr,
1065  NULL);
1066 
1067  MonthCalReload(infoPtr);
1068  break;
1069  }
1070 
1071  case WM_DESTROY:
1072  {
1074  0,
1075  infoPtr);
1077  0,
1078  (DWORD_PTR)NULL);
1079  break;
1080  }
1081 
1082  default:
1083  {
1084 HandleDefaultMessage:
1085  Ret = DefWindowProcW(hwnd,
1086  uMsg,
1087  wParam,
1088  lParam);
1089  break;
1090  }
1091  }
1092 
1093  return Ret;
1094 }
1095 
1096 BOOL
1098 {
1099  WNDCLASSW wc = {0};
1100 
1101  wc.style = CS_DBLCLKS;
1103  wc.cbWndExtra = sizeof(PMONTHCALWND);
1104  wc.hInstance = hInstance;
1105  wc.hCursor = LoadCursorW(NULL,
1106  (LPWSTR)IDC_ARROW);
1107  wc.hbrBackground = (HBRUSH)(MONTHCAL_CTRLBG + 1);
1109 
1110  return RegisterClassW(&wc) != 0;
1111 }
1112 
1113 VOID
1115 {
1117  hInstance);
1118 }
WORD Month
Definition: monthcal.c:36
#define WS_DISABLED
Definition: pedump.c:621
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
#define MCCM_SETDATE
Definition: timedate.h:81
#define IN
Definition: typedefs.h:39
static VOID MonthCalChange(IN PMONTHCALWND infoPtr)
Definition: monthcal.c:313
HWND WINAPI GetAncestor(_In_ HWND, _In_ UINT)
BOOL WINAPI InflateRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define MAKEWPARAM(l, h)
Definition: winuser.h:3985
UINT style
Definition: winuser.h:3152
#define WM_GETDLGCODE
Definition: winuser.h:1672
#define WM_LBUTTONDOWN
Definition: winuser.h:1759
#define MONTHCAL_DISABLED_HEADERBG
Definition: monthcal.c:22
BOOL WINAPI UnregisterClassW(_In_ LPCWSTR, HINSTANCE)
WORD wMonth
Definition: winbase.h:900
#define TRUE
Definition: types.h:120
#define MCCM_RESET
Definition: timedate.h:83
#define LOCALE_SABBREVDAYNAME1
Definition: winnls.h:84
#define LOCALE_USER_DEFAULT
WCHAR Week[7]
Definition: monthcal.c:40
UINT Changed
Definition: monthcal.c:49
BOOL WINAPI DrawFocusRect(_In_ HDC, _In_ LPCRECT)
static WORD LeapYear(IN WORD Year)
Definition: monthcal.c:84
#define INT
Definition: polytest.cpp:20
static HDC
Definition: imagelist.c:92
#define CALLBACK
Definition: compat.h:35
static VOID MonthCalSetLocalTime(IN PMONTHCALWND infoPtr, OUT SYSTEMTIME *Time)
Definition: monthcal.c:397
#define CLR_INVALID
Definition: wingdi.h:882
LONG top
Definition: windef.h:307
static WORD MonthCalWeekInMonth(IN WORD Day, IN WORD DayOfWeek)
Definition: monthcal.c:113
#define GET_X_LPARAM(lp)
Definition: windowsx.h:274
#define VK_LEFT
Definition: winuser.h:2200
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1499
#define ZeroMemory
Definition: winbase.h:1664
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
#define MONTHCAL_DISABLED_HEADERFG
Definition: monthcal.c:23
HWND WINAPI SetFocus(_In_opt_ HWND)
static BOOL MonthCalSetDate(IN PMONTHCALWND infoPtr, IN WORD Day, IN WORD Month, IN WORD Year)
Definition: monthcal.c:328
UINT_PTR WPARAM
Definition: windef.h:207
#define VK_TAB
Definition: winuser.h:2175
#define VK_DOWN
Definition: winuser.h:2203
#define GetWindowLongPtrW
Definition: winuser.h:4805
LONG left
Definition: windef.h:306
#define swprintf
Definition: precomp.h:40
BOOL WINAPI EndPaint(_In_ HWND, _In_ const PAINTSTRUCT *)
static VOID MonthCalSetupDayTimer(IN PMONTHCALWND infoPtr)
Definition: monthcal.c:227
LONG right
Definition: windef.h:308
#define DT_NOPREFIX
Definition: winuser.h:537
#define DWORD
Definition: nt_native.h:44
int32_t INT
Definition: typedefs.h:58
DWORD WINAPI GetSysColor(_In_ int)
WPARAM wParam
Definition: combotst.c:138
#define MCCM_CHANGED
Definition: timedate.h:84
#define ID_DAYTIMER
Definition: monthcal.c:29
HFONT hFont
Definition: main.c:53
struct tagNMHDR * LPNMHDR
#define WM_ENABLE
Definition: winuser.h:1598
#define WM_PRINTCLIENT
Definition: richedit.h:70
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL RegisterMonthCalControl(IN HINSTANCE hInstance)
Definition: monthcal.c:1097
SYSTEMTIME SystemTime
Definition: timedate.h:101
INT WINAPI GetLocaleInfoW(LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len)
Definition: lang.c:1098
UINT code
Definition: winuser.h:3135
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:977
SIZE CellSize
Definition: monthcal.c:41
ATOM WINAPI RegisterClassW(_In_ CONST WNDCLASSW *)
static VOID MonthCalUpdate(IN PMONTHCALWND infoPtr)
Definition: monthcal.c:168
WORD wYear
Definition: winbase.h:899
int WINAPI SetBkMode(_In_ HDC, _In_ int)
Definition: dc.c:1034
HINSTANCE hInstance
Definition: charmap.c:20
#define MONTHCAL_DISABLED_CTRLFG
Definition: monthcal.c:25
#define VK_UP
Definition: winuser.h:2201
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define GA_PARENT
Definition: winuser.h:2764
HDC WINAPI BeginPaint(_In_ HWND, _Out_ LPPAINTSTRUCT)
UINT_PTR idFrom
Definition: winuser.h:3134
UINT Enabled
Definition: monthcal.c:51
WNDPROC lpfnWndProc
Definition: winuser.h:3153
static VOID MonthCalReload(IN PMONTHCALWND infoPtr)
Definition: monthcal.c:252
#define TRANSPARENT
Definition: wingdi.h:949
WORD wMinute
Definition: winbase.h:904
#define WM_GETFONT
Definition: winuser.h:1634
LONG cx
Definition: windef.h:334
#define WM_KEYDOWN
Definition: winuser.h:1698
LPCWSTR lpszClassName
Definition: winuser.h:3161
LONG_PTR LPARAM
Definition: windef.h:208
GLint GLint bottom
Definition: glext.h:7726
VOID WINAPI GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:286
#define DT_VCENTER
Definition: winuser.h:543
#define MONTHCAL_CTRLFG
Definition: monthcal.c:19
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define WM_DESTROY
Definition: winuser.h:1592
#define WM_RBUTTONDOWN
Definition: winuser.h:1762
SIZE ClientSize
Definition: monthcal.c:42
struct tagSTYLESTRUCT * LPSTYLESTRUCT
HBRUSH hbHeader
Definition: monthcal.c:45
#define WM_KILLFOCUS
Definition: winuser.h:1597
#define GetProcessHeap()
Definition: compat.h:595
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
int cbWndExtra
Definition: winuser.h:3155
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define WM_SIZE
Definition: winuser.h:1594
DWORD COLORREF
Definition: windef.h:300
#define MONTHCAL_HEADERBG
Definition: monthcal.c:16
#define MONTHCAL_DISABLED_CTRLBG
Definition: monthcal.c:24
#define WM_TIMER
Definition: winuser.h:1725
WORD FirstDayOfWeek
Definition: monthcal.c:38
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
unsigned short WORD
Definition: ntddk_ex.h:93
int WINAPI GetSystemMetrics(_In_ int)
unsigned long DWORD
Definition: ntddk_ex.h:95
#define MONTHCAL_SELFG
Definition: monthcal.c:21
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2074
GLdouble GLdouble right
Definition: glext.h:10859
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
static HFONT MonthCalChangeFont(IN PMONTHCALWND infoPtr, IN HFONT hFont, IN BOOL Redraw)
Definition: monthcal.c:643
WORD wSecond
Definition: winbase.h:905
#define WM_PAINT
Definition: winuser.h:1603
#define MCCN_SELCHANGE
Definition: timedate.h:86
WORD wMilliseconds
Definition: winbase.h:906
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
DWORD UIState
Definition: monthcal.c:48
static const WCHAR L[]
Definition: oid.c:1250
static WORD MonthCalDayOfWeek(IN PMONTHCALWND infoPtr, IN WORD Day, IN WORD Month, IN WORD Year)
Definition: monthcal.c:120
BOOL WINAPI GetUpdateRect(_In_ HWND, _Out_opt_ LPRECT, _In_ BOOL)
#define MONTHCAL_DISABLED_SELFG
Definition: monthcal.c:27
#define WM_LBUTTONDBLCLK
Definition: winuser.h:1761
#define LRESULT
Definition: ole.h:14
WORD Day
Definition: monthcal.c:35
#define CS_DBLCLKS
Definition: winuser.h:646
static LRESULT MonthCalNotifyControlParent(IN PMONTHCALWND infoPtr, IN UINT code, IN OUT PVOID data)
Definition: monthcal.c:56
Definition: inflate.c:139
HWND hwndFrom
Definition: winuser.h:3133
uint32_t DWORD_PTR
Definition: typedefs.h:65
BOOL WINAPI TextOutW(_In_ HDC hdc, _In_ int x, _In_ int y, _In_reads_(c) LPCWSTR lpString, _In_ int c)
#define LOCALE_IFIRSTDAYOFWEEK
Definition: winnls.h:75
unsigned char BYTE
Definition: xxhash.c:193
static WORD MonthCalFirstDayOfWeek(VOID)
Definition: monthcal.c:135
int code
Definition: main.c:75
#define VK_RIGHT
Definition: winuser.h:2202
static BOOL(WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX *)
HCURSOR hCursor
Definition: winuser.h:3158
#define GWL_STYLE
Definition: winuser.h:846
COLORREF WINAPI SetTextColor(_In_ HDC, _In_ COLORREF)
Definition: text.c:898
static HDC hDC
Definition: 3dtext.c:33
WORD wDay
Definition: winbase.h:902
#define DT_SINGLELINE
Definition: winuser.h:540
HBRUSH hbSelection
Definition: monthcal.c:46
WORD Year
Definition: monthcal.c:37
#define MONTHCAL_CTRLBG
Definition: monthcal.c:18
#define TEXT(s)
Definition: k32.h:26
static VOID MonthCalRepaintDay(IN PMONTHCALWND infoPtr, IN WORD Day)
Definition: monthcal.c:437
VOID UnregisterMonthCalControl(IN HINSTANCE hInstance)
Definition: monthcal.c:1114
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static WORD MonthCalPtToDay(IN PMONTHCALWND infoPtr, IN INT x, IN INT y)
Definition: monthcal.c:661
HBRUSH hbrBackground
Definition: winuser.h:3159
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
struct tagCREATESTRUCTW * LPCREATESTRUCTW
struct _MONTHCALWND * PMONTHCALWND
#define WM_MBUTTONDOWN
Definition: winuser.h:1765
WORD wHour
Definition: winbase.h:903
#define MONTHCAL_HEADERFG
Definition: monthcal.c:17
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
HWND hNotify
Definition: monthcal.c:34
unsigned int UINT
Definition: ndis.h:50
#define NULL
Definition: types.h:112
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
static BOOL MonthCalGetDayRect(IN PMONTHCALWND infoPtr, IN WORD Day, OUT RECT *rcCell)
Definition: monthcal.c:286
UINT HasFocus
Definition: monthcal.c:52
#define WM_SETFONT
Definition: winuser.h:1633
HWND hSelf
Definition: monthcal.c:33
static const WCHAR szMonthCalWndClass[]
Definition: monthcal.c:14
#define GET_Y_LPARAM(lp)
Definition: windowsx.h:275
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
HINSTANCE hInstance
Definition: winuser.h:3156
UINT DayTimerSet
Definition: monthcal.c:50
static VOID MonthCalPaint(IN PMONTHCALWND infoPtr, IN HDC hDC, IN LPRECT prcUpdate)
Definition: monthcal.c:453
#define IDC_ARROW
Definition: winuser.h:682
#define MCCM_GETDATE
Definition: timedate.h:82
#define OUT
Definition: typedefs.h:40
#define WM_CREATE
Definition: winuser.h:1591
#define HIWORD(l)
Definition: typedefs.h:247
#define MONTHCAL_DISABLED_SELBG
Definition: monthcal.c:26
LONG bottom
Definition: windef.h:309
#define DT_CENTER
Definition: winuser.h:527
static LRESULT CALLBACK MonthCalWndProc(IN HWND hwnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
Definition: monthcal.c:683
#define SetWindowLongPtrW
Definition: winuser.h:5322
static WORD MonthCalMonthLength(IN WORD Month, IN WORD Year)
Definition: monthcal.c:94
#define WM_ERASEBKGND
Definition: winuser.h:1608
#define WM_SETFOCUS
Definition: winuser.h:1596
struct _MONTHCALWND MONTHCALWND
WCHAR * LPWSTR
Definition: xmlstorage.h:184
LONG_PTR LRESULT
Definition: windef.h:209
#define MONTHCAL_SELBG
Definition: monthcal.c:20
int WINAPI FillRect(HDC, LPCRECT, HBRUSH)
struct _SYSTEMTIME * LPSYSTEMTIME
Definition: time.c:27
HBRUSH WINAPI GetSysColorBrush(_In_ int)
LONG cy
Definition: windef.h:335
BYTE * PBYTE
Definition: pedump.c:66
HFONT hFont
Definition: monthcal.c:44
LPARAM lParam
Definition: combotst.c:139
#define LOWORD(l)
Definition: pedump.c:82
#define HeapFree(x, y, z)
Definition: compat.h:594
#define GWLP_ID
Definition: winuser.h:854
#define DLGC_WANTARROWS
Definition: winuser.h:2586
static PLARGE_INTEGER Time
Definition: time.c:105
BOOL WINAPI GetTextExtentPoint32W(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpString, _In_ int c, _Out_ LPSIZE psizl)
#define WM_NOTIFY
Definition: richedit.h:61
#define d
Definition: ke_i.h:81
#define MCCN_AUTOUPDATE
Definition: timedate.h:97
static BOOL MonthCalValidDate(IN WORD Day, IN WORD Month, IN WORD Year)
Definition: monthcal.c:152
INT WINAPI DrawTextW(HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags)
Definition: defwnd.c:17
BYTE Days[6][7]
Definition: monthcal.c:39