2 * Date and time picker control
4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 1999, 2000 Alex Priem <alexp@sci.kun.nl>
6 * Copyright 2000 Chris Morgan <cmorgan@wpi.edu>
11 * - All notifications.
21 #include "wine/winestring.h"
23 #include "debugtools.h"
25 DEFAULT_DEBUG_CHANNEL(datetime);
34 RECT rcClient; /* rect around the edge of the window */
35 RECT rcDraw; /* rect inside of the border */
36 RECT checkbox; /* checkbox allowing the control to be enabled/disabled */
37 RECT calbutton; /* button that toggles the dropdown of the monthcal control */
38 BOOL bCalDepressed; /* TRUE = cal button is depressed */
41 int nrFieldsAllocated;
49 } DATETIME_INFO, *LPDATETIME_INFO;
52 extern const int mdays[];
53 extern const char * const monthtxt[];
55 /* this list of defines is closely related to `allowedformatchars' defined
56 * in datetime.c; the high nibble indicates the `base type' of the format
58 * Do not change without first reading DATETIME_UseFormat.
62 #define DT_END_FORMAT 0
63 #define ONEDIGITDAY 0x01
64 #define TWODIGITDAY 0x02
65 #define THREECHARDAY 0x03
67 #define ONEDIGIT12HOUR 0x11
68 #define TWODIGIT12HOUR 0x12
69 #define ONEDIGIT24HOUR 0x21
70 #define TWODIGIT24HOUR 0x22
71 #define ONEDIGITMINUTE 0x31
72 #define TWODIGITMINUTE 0x32
73 #define ONEDIGITMONTH 0x41
74 #define TWODIGITMONTH 0x42
75 #define THREECHARMONTH 0x43
76 #define FULLMONTH 0x44
77 #define ONEDIGITSECOND 0x51
78 #define TWODIGITSECOND 0x52
79 #define ONELETTERAMPM 0x61
80 #define TWOLETTERAMPM 0x62
81 #define ONEDIGITYEAR 0x71
82 #define TWODIGITYEAR 0x72
84 #define FORMATCALLBACK 0x81 /* -> maximum of 0x80 callbacks possible */
85 #define FORMATCALLMASK 0x80
86 #define DT_STRING 0x0100
88 #define DTHT_DATEFIELD 0xff /* for hit-testing */
91 #define DTHT_CHECKBOX 0x200 /* these should end at '00' , to make */
92 #define DTHT_MCPOPUP 0x300 /* & DTHT_DATEFIELD 0 when DATETIME_KeyDown */
93 #define DTHT_GOTFOCUS 0x400 /* tests for date-fields */
95 #define DATETIME_GetInfoPtr(hwnd) ((DATETIME_INFO *)GetWindowLongA (hwnd, 0))
97 static BOOL DATETIME_SendSimpleNotify (HWND hwnd, UINT code);
98 static BOOL DATETIME_SendDateTimeChangeNotify (HWND hwnd);
99 extern void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to);
100 static const char * const days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
101 "Thursday", "Friday", "Saturday", NULL};
102 static const char *allowedformatchars = {"dhHmMstyX'"};
103 static const int maxrepetition [] = {4,2,2,2,4,2,2,3,-1,-1};
107 DATETIME_GetSystemTime (HWND hwnd, WPARAM wParam, LPARAM lParam )
109 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
110 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
111 SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *) lParam;
113 if (!lParam) return GDT_NONE;
115 if ((dwStyle & DTS_SHOWNONE) &&
116 (SendMessageA (infoPtr->hwndCheckbut, BM_GETCHECK, 0, 0)))
119 MONTHCAL_CopyTime (&infoPtr->date, lprgSysTimeArray);
126 DATETIME_SetSystemTime (HWND hwnd, WPARAM wParam, LPARAM lParam )
128 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
129 SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *) lParam;
131 if (!lParam) return 0;
133 if (lParam==GDT_VALID)
134 MONTHCAL_CopyTime (lprgSysTimeArray, &infoPtr->date);
135 if (lParam==GDT_NONE) {
136 infoPtr->dateValid=FALSE;
137 SendMessageA (infoPtr->hwndCheckbut, BM_SETCHECK, 0, 0);
144 DATETIME_GetMonthCalColor (HWND hwnd, WPARAM wParam)
146 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
148 return SendMessageA (infoPtr->hMonthCal, MCM_GETCOLOR, wParam, 0);
153 DATETIME_SetMonthCalColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
155 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
157 return SendMessageA (infoPtr->hMonthCal, MCM_SETCOLOR, wParam, lParam);
161 /* FIXME: need to get way to force font into monthcal structure */
163 DATETIME_GetMonthCal (HWND hwnd)
165 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
167 return infoPtr->hMonthCal;
172 /* FIXME: need to get way to force font into monthcal structure */
175 DATETIME_GetMonthCalFont (HWND hwnd)
183 DATETIME_SetMonthCalFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
191 Split up a formattxt in actions.
192 See ms documentation for the meaning of the letter codes/'specifiers'.
195 *'dddddd' is handled as 'dddd' plus 'dd'.
196 *unrecognized formats are strings (here given the type DT_STRING;
197 start of the string is encoded in lower bits of DT_STRING.
198 Therefore, 'string' ends finally up as '<show seconds>tring'.
204 DATETIME_UseFormat (DATETIME_INFO *infoPtr, const char *formattxt)
207 int *nrFields=& infoPtr->nrFields;
209 TRACE ("%s\n",formattxt);
213 infoPtr->fieldspec[*nrFields]=0;
214 len=strlen(allowedformatchars);
217 for (i=0; i<strlen (formattxt); i++) {
218 TRACE ("\n%d %c:",i, formattxt[i]);
219 for (j=0; j<len; j++) {
220 if (allowedformatchars[j]==formattxt[i]) {
221 TRACE ("%c[%d,%x]",allowedformatchars[j], *nrFields,
222 infoPtr->fieldspec[*nrFields]);
223 if ((*nrFields==0) && (infoPtr->fieldspec[*nrFields]==0)) {
224 infoPtr->fieldspec[*nrFields]=(j<<4) +1;
227 if (infoPtr->fieldspec[*nrFields]>>4!=j) {
229 infoPtr->fieldspec[*nrFields]=(j<<4) +1;
232 if ((infoPtr->fieldspec[*nrFields] & 0x0f)==maxrepetition[j]) {
234 infoPtr->fieldspec[*nrFields]=(j<<4) +1;
237 infoPtr->fieldspec[*nrFields]++;
239 } /* if allowedformatchar */
243 /* char is not a specifier: handle char like a string */
245 if ((*nrFields==0) && (infoPtr->fieldspec[*nrFields]==0)) {
246 infoPtr->fieldspec[*nrFields]=DT_STRING+k;
247 infoPtr->buflen[*nrFields]=0;
249 if ((infoPtr->fieldspec[*nrFields] & DT_STRING)!=DT_STRING) {
251 infoPtr->fieldspec[*nrFields]=DT_STRING+k;
252 infoPtr->buflen[*nrFields]=0;
254 infoPtr->textbuf[k]=formattxt[i];
256 infoPtr->buflen[*nrFields]++;
259 if (*nrFields==infoPtr->nrFieldsAllocated) {
260 FIXME ("out of memory; should reallocate. crash ahead.\n");
267 if (infoPtr->fieldspec[*nrFields]!=0) (*nrFields)++;
272 DATETIME_SetFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
274 DATETIME_INFO *infoPtr= DATETIME_GetInfoPtr (hwnd);
277 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
279 if (dwStyle & DTS_LONGDATEFORMAT)
280 DATETIME_UseFormat (infoPtr, "dddd, MMMM dd, yyy");
281 else if (dwStyle & DTS_TIMEFORMAT)
282 DATETIME_UseFormat (infoPtr, "h:mm:ss tt");
283 else /* DTS_SHORTDATEFORMAT */
284 DATETIME_UseFormat (infoPtr, "M/d/yy");
287 DATETIME_UseFormat (infoPtr, (char *) lParam);
289 return infoPtr->nrFields;
294 DATETIME_SetFormatW (HWND hwnd, WPARAM wParam, LPARAM lParam)
300 int len = lstrlenW ((LPWSTR) lParam)+1;
302 buf = (LPSTR) COMCTL32_Alloc (len);
303 lstrcpyWtoA (buf, (LPWSTR) lParam);
304 retval=DATETIME_SetFormat (hwnd, 0, (LPARAM) buf);
309 return DATETIME_SetFormat (hwnd, 0, 0);
315 DATETIME_ReturnTxt (DATETIME_INFO *infoPtr, int count, char *result)
317 SYSTEMTIME date = infoPtr->date;
321 TRACE ("%d,%d\n", infoPtr->nrFields, count);
322 if ((count>infoPtr->nrFields) || (count<0)) {
323 WARN ("buffer overrun, have %d want %d\n", infoPtr->nrFields, count);
327 if (!infoPtr->fieldspec) return;
329 spec=infoPtr->fieldspec[count];
330 if (spec & DT_STRING) {
331 int txtlen=infoPtr->buflen[count];
333 strncpy (result, infoPtr->textbuf + (spec &~ DT_STRING), txtlen);
335 TRACE ("arg%d=%x->[%s]\n",count,infoPtr->fieldspec[count],result);
345 sprintf (result,"%d",date.wDay);
348 sprintf (result,"%.2d",date.wDay);
351 sprintf (result,"%.3s",days[date.wDayOfWeek]);
354 strcpy (result,days[date.wDayOfWeek]);
358 sprintf (result,"%d",date.wHour-12);
360 sprintf (result,"%d",date.wHour);
364 sprintf (result,"%.2d",date.wHour-12);
366 sprintf (result,"%.2d",date.wHour);
369 sprintf (result,"%d",date.wHour);
372 sprintf (result,"%.2d",date.wHour);
375 sprintf (result,"%d",date.wSecond);
378 sprintf (result,"%.2d",date.wSecond);
381 sprintf (result,"%d",date.wMinute);
384 sprintf (result,"%.2d",date.wMinute);
387 sprintf (result,"%d",date.wMonth);
390 sprintf (result,"%.2d",date.wMonth);
393 sprintf (result,"%.3s",monthtxt[date.wMonth-1]);
396 strcpy (result,monthtxt[date.wMonth-1]);
406 strcpy (result,"AM");
408 strcpy (result,"PM");
411 FIXME ("Not implemented\n");
412 strcpy (result,"xxx");
415 sprintf (result,"%d",date.wYear-10* (int) floor(date.wYear/10));
418 sprintf (result,"%.2d",date.wYear-100* (int) floor(date.wYear/100));
421 sprintf (result,"%d",date.wYear);
425 TRACE ("arg%d=%x->[%s]\n",count,infoPtr->fieldspec[count],result);
430 DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number)
432 SYSTEMTIME *date = &infoPtr->date;
435 TRACE ("%d\n",number);
436 if ((number>infoPtr->nrFields) || (number<0)) return;
438 spec=infoPtr->fieldspec[number];
439 if ((spec & DTHT_DATEFIELD)==0) return;
447 if (date->wDay>mdays[date->wMonth-1]) date->wDay=1;
454 if (date->wHour>23) date->wHour=0;
459 if (date->wSecond>59) date->wSecond=0;
464 if (date->wMinute>59) date->wMinute=0;
471 if (date->wMonth>12) date->wMonth=1;
472 if (date->wDay>mdays[date->wMonth-1])
473 date->wDay=mdays[date->wMonth-1];
478 if (date->wHour>23) date->wHour-=24;
481 FIXME ("Not implemented\n");
494 DATETIME_DecreaseField (DATETIME_INFO *infoPtr, int number)
496 SYSTEMTIME *date = & infoPtr->date;
499 TRACE ("%d\n",number);
500 if ((number>infoPtr->nrFields) || (number<0)) return;
502 spec = infoPtr->fieldspec[number];
503 if ((spec & DTHT_DATEFIELD)==0) return;
513 if (date->wDay<1) date->wDay=mdays[date->wMonth-1];
546 if (date->wDay>mdays[date->wMonth-1])
547 date->wDay=mdays[date->wMonth-1];
557 FIXME ("Not implemented\n");
570 DATETIME_ResetFieldDown (DATETIME_INFO *infoPtr, int number)
572 SYSTEMTIME *date = &infoPtr->date;
575 TRACE ("%d\n",number);
576 if ((number>infoPtr->nrFields) || (number<0)) return;
578 spec = infoPtr->fieldspec[number];
579 if ((spec & DTHT_DATEFIELD)==0) return;
611 FIXME ("Not implemented\n");
615 /* FYI: On 9/14/1752 the calender changed and England and the American */
616 /* colonies changed to the Gregorian calender. This change involved */
617 /* having September 14th following September 2nd. So no date algorithms */
618 /* work before that date. */
623 date->wDay = 14; /* overactive ms-programmers..*/
633 DATETIME_ResetFieldUp (DATETIME_INFO *infoPtr, int number)
635 SYSTEMTIME *date = & infoPtr->date;
638 if ((number>infoPtr->nrFields) || (number<0)) return;
640 spec=infoPtr->fieldspec[number];
641 if ((spec & DTHT_DATEFIELD)==0) return;
648 date->wDay=mdays[date->wMonth-1];
672 FIXME ("Not implemented\n");
677 date->wYear=9999; /* Y10K problem? naaah. */
684 static void DATETIME_Refresh (HWND hwnd, HDC hdc)
687 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
690 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
691 RECT *rcDraw = &infoPtr->rcDraw;
692 RECT *rcClient = &infoPtr->rcClient;
693 RECT *calbutton = &infoPtr->calbutton;
694 RECT *checkbox = &infoPtr->checkbox;
697 COLORREF oldBk, oldTextColor;
699 /* draw control edge */
700 hbr = CreateSolidBrush(RGB(255, 255, 255));
701 FillRect(hdc, rcClient, hbr);
702 DrawEdge(hdc, rcClient, EDGE_SUNKEN, BF_RECT);
705 if (infoPtr->dateValid) {
708 oldFont = SelectObject (hdc, infoPtr->hFont);
710 DATETIME_ReturnTxt (infoPtr, 0, txt);
711 GetTextExtentPoint32A (hdc, txt, strlen (txt), &size);
712 rcDraw->bottom = size.cy+2;
714 if (dwStyle & DTS_SHOWNONE) checkbox->right = 18;
716 prevright = checkbox->right;
718 for (i=0; i<infoPtr->nrFields; i++) {
719 DATETIME_ReturnTxt (infoPtr, i, txt);
720 GetTextExtentPoint32A (hdc, txt, strlen (txt), &size);
721 field = & infoPtr->fieldRect[i];
722 field->left = prevright;
723 field->right = prevright+size.cx;
724 field->top = rcDraw->top;
725 field->bottom = rcDraw->bottom;
726 prevright = field->right;
728 if ((infoPtr->haveFocus) && (i==infoPtr->select)) {
729 hbr = CreateSolidBrush (GetSysColor (COLOR_ACTIVECAPTION));
730 FillRect(hdc, field, hbr);
731 oldBk = SetBkColor (hdc, GetSysColor(COLOR_ACTIVECAPTION));
732 oldTextColor = SetTextColor (hdc, GetSysColor(COLOR_WINDOW));
734 DrawTextA ( hdc, txt, strlen(txt), field,
735 DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
736 SetBkColor (hdc, oldBk);
737 SetTextColor (hdc, oldTextColor);
740 DrawTextA ( hdc, txt, strlen(txt), field,
741 DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
744 SelectObject (hdc, oldFont);
747 if (!(dwStyle & DTS_UPDOWN)) {
748 DrawFrameControl(hdc, calbutton, DFC_SCROLL,
749 DFCS_SCROLLDOWN | (infoPtr->bCalDepressed ? DFCS_PUSHED : 0) |
750 (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
756 DATETIME_HitTest (HWND hwnd, DATETIME_INFO *infoPtr, POINT pt)
760 TRACE ("%ld, %ld\n",pt.x,pt.y);
763 if (PtInRect (&infoPtr->calbutton, pt))
764 {retval = DTHT_MCPOPUP; TRACE("Hit in calbutton(DTHT_MCPOPUP)\n"); goto done; }
765 if (PtInRect (&infoPtr->checkbox, pt))
766 {retval = DTHT_CHECKBOX; TRACE("Hit in checkbox(DTHT_CHECKBOX)\n"); goto done; }
768 for (i=0; i<infoPtr->nrFields; i++) {
769 if (PtInRect (&infoPtr->fieldRect[i], pt)) {
771 TRACE("Hit in date text in field %d\n", i);
782 DATETIME_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
784 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
785 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
791 old = infoPtr->select;
792 pt.x = (INT)LOWORD(lParam);
793 pt.y = (INT)HIWORD(lParam);
795 new = DATETIME_HitTest (hwnd, infoPtr, pt);
797 /* FIXME: might be conditions where we don't want to update infoPtr->select */
798 infoPtr->select = new;
800 if (infoPtr->select != old) {
801 infoPtr->haveFocus = DTHT_GOTFOCUS;
804 if (infoPtr->select == DTHT_MCPOPUP) {
805 /* FIXME: button actually is only depressed during dropdown of the */
806 /* calender control and when the mouse is over the button window */
807 infoPtr->bCalDepressed = TRUE;
809 /* recalculate the position of the monthcal popup */
810 if(dwStyle & DTS_RIGHTALIGN)
811 infoPtr->monthcal_pos.x = infoPtr->rcClient.right - ((infoPtr->calbutton.right -
812 infoPtr->calbutton.left) + 145);
814 infoPtr->monthcal_pos.x = 8;
816 infoPtr->monthcal_pos.y = infoPtr->rcClient.bottom;
817 ClientToScreen (hwnd, &(infoPtr->monthcal_pos));
818 SetWindowPos(infoPtr->hMonthCal, 0, infoPtr->monthcal_pos.x,
819 infoPtr->monthcal_pos.y, 145, 150, 0);
821 if(IsWindowVisible(infoPtr->hMonthCal))
822 ShowWindow(infoPtr->hMonthCal, SW_HIDE);
824 ShowWindow(infoPtr->hMonthCal, SW_SHOW);
826 TRACE ("dt:%x mc:%x mc parent:%x, desktop:%x, mcpp:%x\n",
827 hwnd,infoPtr->hMonthCal,
828 GetParent (infoPtr->hMonthCal),
830 GetParent (GetParent (infoPtr->hMonthCal)));
831 DATETIME_SendSimpleNotify (hwnd, DTN_DROPDOWN);
834 InvalidateRect(hwnd, NULL, FALSE);
841 DATETIME_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
843 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
847 if(infoPtr->bCalDepressed == TRUE) {
848 infoPtr->bCalDepressed = FALSE;
849 InvalidateRect(hwnd, &(infoPtr->calbutton), TRUE);
857 DATETIME_Paint (HWND hwnd, WPARAM wParam)
862 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
863 DATETIME_Refresh (hwnd, hdc);
865 EndPaint (hwnd, &ps);
871 DATETIME_ParentNotify (HWND hwnd, WPARAM wParam, LPARAM lParam)
873 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
874 LPNMHDR lpnmh = (LPNMHDR) lParam;
876 TRACE ("%x,%lx\n",wParam, lParam);
877 TRACE ("Got notification %x from %x\n", lpnmh->code, lpnmh->hwndFrom);
878 TRACE ("info: %x %x %x\n",hwnd,infoPtr->hMonthCal,infoPtr->hUpdown);
884 DATETIME_Notify (HWND hwnd, WPARAM wParam, LPARAM lParam)
887 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
888 LPNMHDR lpnmh = (LPNMHDR) lParam;
890 TRACE ("%x,%lx\n",wParam, lParam);
891 TRACE ("Got notification %x from %x\n", lpnmh->code, lpnmh->hwndFrom);
892 TRACE ("info: %x %x %x\n",hwnd,infoPtr->hMonthCal,infoPtr->hUpdown);
898 DATETIME_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
900 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
903 TRACE("%x %lx %x\n",wParam, lParam, infoPtr->select);
905 FieldNum = infoPtr->select & DTHT_DATEFIELD;
907 if (!(infoPtr->haveFocus)) return 0;
908 if ((FieldNum==0) && (infoPtr->select)) return 0;
910 if (infoPtr->select & FORMATCALLMASK) {
911 FIXME ("Callbacks not implemented yet\n");
917 DATETIME_IncreaseField (infoPtr,FieldNum);
918 DATETIME_SendDateTimeChangeNotify (hwnd);
922 DATETIME_DecreaseField (infoPtr,FieldNum);
923 DATETIME_SendDateTimeChangeNotify (hwnd);
926 DATETIME_ResetFieldDown (infoPtr,FieldNum);
927 DATETIME_SendDateTimeChangeNotify (hwnd);
930 DATETIME_ResetFieldUp(infoPtr,FieldNum);
931 DATETIME_SendDateTimeChangeNotify (hwnd);
935 if (infoPtr->select==0) {
936 infoPtr->select = infoPtr->nrFields - 1;
941 while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2));
946 if (infoPtr->select==infoPtr->nrFields) {
951 while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2));
955 InvalidateRect(hwnd, NULL, FALSE);
962 DATETIME_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
964 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
968 if (infoPtr->haveFocus) {
969 DATETIME_SendSimpleNotify (hwnd, NM_KILLFOCUS);
970 infoPtr->haveFocus = 0;
973 InvalidateRect (hwnd, NULL, TRUE);
980 DATETIME_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
982 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
986 if (infoPtr->haveFocus==0) {
987 DATETIME_SendSimpleNotify (hwnd, NM_SETFOCUS);
988 infoPtr->haveFocus = DTHT_GOTFOCUS;
991 InvalidateRect(hwnd, NULL, FALSE);
998 DATETIME_SendDateTimeChangeNotify (HWND hwnd)
1001 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
1002 NMDATETIMECHANGE dtdtc;
1005 dtdtc.nmhdr.hwndFrom = hwnd;
1006 dtdtc.nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
1007 dtdtc.nmhdr.code = DTN_DATETIMECHANGE;
1009 if ((GetWindowLongA (hwnd, GWL_STYLE) & DTS_SHOWNONE))
1010 dtdtc.dwFlags = GDT_NONE;
1012 dtdtc.dwFlags = GDT_VALID;
1014 MONTHCAL_CopyTime (&infoPtr->date, &dtdtc.st);
1015 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
1016 (WPARAM)dtdtc.nmhdr.idFrom, (LPARAM)&dtdtc);
1021 DATETIME_SendSimpleNotify (HWND hwnd, UINT code)
1026 nmhdr.hwndFrom = hwnd;
1027 nmhdr.idFrom = GetWindowLongA( hwnd, GWL_ID);
1030 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
1031 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1035 DATETIME_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1037 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr(hwnd);
1038 DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
1041 infoPtr->rcClient.bottom = HIWORD(lParam);
1042 infoPtr->rcClient.right = LOWORD(lParam);
1044 TRACE("Height=%d, Width=%d\n", infoPtr->rcClient.bottom, infoPtr->rcClient.right);
1046 /* use DrawEdge to adjust the size of rcEdge to get rcDraw */
1047 memcpy((&infoPtr->rcDraw), (&infoPtr->rcClient), sizeof(infoPtr->rcDraw));
1049 DrawEdge((HDC)NULL, &(infoPtr->rcDraw), EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1051 /* set the size of the button that drops the calender down */
1052 /* FIXME: account for style that allows button on left side */
1053 infoPtr->calbutton.top = infoPtr->rcDraw.top;
1054 infoPtr->calbutton.bottom= infoPtr->rcDraw.bottom;
1055 infoPtr->calbutton.left = infoPtr->rcDraw.right-15;
1056 infoPtr->calbutton.right = infoPtr->rcDraw.right;
1058 /* set enable/disable button size for show none style being enabled */
1059 /* FIXME: these dimensions are completely incorrect */
1060 infoPtr->checkbox.top = infoPtr->rcDraw.top;
1061 infoPtr->checkbox.bottom = infoPtr->rcDraw.bottom;
1062 infoPtr->checkbox.left = infoPtr->rcDraw.left;
1063 infoPtr->checkbox.right = infoPtr->rcDraw.left + 10;
1065 /* update the position of the monthcal control */
1066 if(dwStyle & DTS_RIGHTALIGN)
1067 infoPtr->monthcal_pos.x = infoPtr->rcClient.right - ((infoPtr->calbutton.right -
1068 infoPtr->calbutton.left) + 145);
1070 infoPtr->monthcal_pos.x = 8;
1072 infoPtr->monthcal_pos.y = infoPtr->rcClient.bottom;
1073 ClientToScreen (hwnd, &(infoPtr->monthcal_pos));
1074 SetWindowPos(infoPtr->hMonthCal, 0, infoPtr->monthcal_pos.x,
1075 infoPtr->monthcal_pos.y,
1078 InvalidateRect(hwnd, NULL, FALSE);
1085 DATETIME_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1087 DATETIME_INFO *infoPtr;
1088 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1090 /* allocate memory for info structure */
1091 infoPtr = (DATETIME_INFO *)COMCTL32_Alloc (sizeof(DATETIME_INFO));
1092 if (infoPtr == NULL) {
1093 ERR("could not allocate info memory!\n");
1097 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
1099 if (dwStyle & DTS_SHOWNONE) {
1100 infoPtr->hwndCheckbut=CreateWindowExA (0,"button", 0,
1101 WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
1104 0, GetWindowLongA (hwnd, GWL_HINSTANCE), 0);
1105 SendMessageA (infoPtr->hwndCheckbut, BM_SETCHECK, 1, 0);
1108 if (dwStyle & DTS_UPDOWN) {
1109 infoPtr->hUpdown=CreateUpDownControl (
1110 WS_CHILD | WS_BORDER | WS_VISIBLE,
1113 UD_MAXVAL, UD_MINVAL, 0);
1116 infoPtr->fieldspec = (int *) COMCTL32_Alloc (32*sizeof(int));
1117 infoPtr->fieldRect = (RECT *) COMCTL32_Alloc (32*sizeof(RECT));
1118 infoPtr->buflen = (int *) COMCTL32_Alloc (32*sizeof(int));
1119 infoPtr->nrFieldsAllocated = 32;
1121 DATETIME_SetFormat (hwnd, 0, 0);
1123 /* create the monthcal control */
1124 infoPtr->hMonthCal = CreateWindowExA (0,"SysMonthCal32", 0,
1125 WS_BORDER | WS_POPUP | WS_CLIPSIBLINGS,
1130 /* initialize info structure */
1131 GetSystemTime (&infoPtr->date);
1132 infoPtr->dateValid = TRUE;
1133 infoPtr->hFont = GetStockObject(DEFAULT_GUI_FONT);
1139 DATETIME_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1141 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
1143 COMCTL32_Free (infoPtr);
1148 static LRESULT WINAPI
1149 DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1154 case DTM_GETSYSTEMTIME:
1155 DATETIME_GetSystemTime (hwnd, wParam, lParam);
1157 case DTM_SETSYSTEMTIME:
1158 DATETIME_SetSystemTime (hwnd, wParam, lParam);
1161 FIXME("Unimplemented msg DTM_GETRANGE\n");
1165 FIXME("Unimplemented msg DTM_SETRANGE\n");
1168 case DTM_SETFORMATA:
1169 return DATETIME_SetFormat (hwnd, wParam, lParam);
1171 case DTM_SETFORMATW:
1172 return DATETIME_SetFormatW (hwnd, wParam, lParam);
1174 case DTM_SETMCCOLOR:
1175 return DATETIME_SetMonthCalColor (hwnd, wParam, lParam);
1177 case DTM_GETMCCOLOR:
1178 return DATETIME_GetMonthCalColor (hwnd, wParam);
1180 case DTM_GETMONTHCAL:
1181 return DATETIME_GetMonthCal (hwnd);
1184 return DATETIME_SetMonthCalFont (hwnd, wParam, lParam);
1187 return DATETIME_GetMonthCalFont (hwnd);
1189 case WM_PARENTNOTIFY:
1190 return DATETIME_ParentNotify (hwnd, wParam, lParam);
1193 return DATETIME_Notify (hwnd, wParam, lParam);
1196 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1199 return DATETIME_Paint (hwnd, wParam);
1202 return DATETIME_KeyDown (hwnd, wParam, lParam);
1205 return DATETIME_KillFocus (hwnd, wParam, lParam);
1208 return DATETIME_SetFocus (hwnd, wParam, lParam);
1211 return DATETIME_Size (hwnd, wParam, lParam);
1213 case WM_LBUTTONDOWN:
1214 return DATETIME_LButtonDown (hwnd, wParam, lParam);
1217 return DATETIME_LButtonUp (hwnd, wParam, lParam);
1220 return DATETIME_Create (hwnd, wParam, lParam);
1223 return DATETIME_Destroy (hwnd, wParam, lParam);
1226 if (uMsg >= WM_USER)
1227 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
1228 uMsg, wParam, lParam);
1229 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1236 DATETIME_Register (void)
1240 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1241 wndClass.style = CS_GLOBALCLASS;
1242 wndClass.lpfnWndProc = (WNDPROC)DATETIME_WindowProc;
1243 wndClass.cbClsExtra = 0;
1244 wndClass.cbWndExtra = sizeof(DATETIME_INFO *);
1245 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
1246 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1247 wndClass.lpszClassName = DATETIMEPICK_CLASSA;
1249 RegisterClassA (&wndClass);
1254 DATETIME_Unregister (void)
1256 UnregisterClassA (DATETIMEPICK_CLASSA, (HINSTANCE)NULL);