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.
22 #include "debugtools.h"
24 DEFAULT_DEBUG_CHANNEL(datetime
);
33 RECT rcClient
; /* rect around the edge of the window */
34 RECT rcDraw
; /* rect inside of the border */
35 RECT checkbox
; /* checkbox allowing the control to be enabled/disabled */
36 RECT calbutton
; /* button that toggles the dropdown of the monthcal control */
37 BOOL bCalDepressed
; /* TRUE = cal button is depressed */
40 int nrFieldsAllocated
;
48 } DATETIME_INFO
, *LPDATETIME_INFO
;
51 extern const int mdays
[];
52 extern const char * const monthtxt
[];
54 /* this list of defines is closely related to `allowedformatchars' defined
55 * in datetime.c; the high nibble indicates the `base type' of the format
57 * Do not change without first reading DATETIME_UseFormat.
61 #define DT_END_FORMAT 0
62 #define ONEDIGITDAY 0x01
63 #define TWODIGITDAY 0x02
64 #define THREECHARDAY 0x03
66 #define ONEDIGIT12HOUR 0x11
67 #define TWODIGIT12HOUR 0x12
68 #define ONEDIGIT24HOUR 0x21
69 #define TWODIGIT24HOUR 0x22
70 #define ONEDIGITMINUTE 0x31
71 #define TWODIGITMINUTE 0x32
72 #define ONEDIGITMONTH 0x41
73 #define TWODIGITMONTH 0x42
74 #define THREECHARMONTH 0x43
75 #define FULLMONTH 0x44
76 #define ONEDIGITSECOND 0x51
77 #define TWODIGITSECOND 0x52
78 #define ONELETTERAMPM 0x61
79 #define TWOLETTERAMPM 0x62
80 #define ONEDIGITYEAR 0x71
81 #define TWODIGITYEAR 0x72
83 #define FORMATCALLBACK 0x81 /* -> maximum of 0x80 callbacks possible */
84 #define FORMATCALLMASK 0x80
85 #define DT_STRING 0x0100
87 #define DTHT_DATEFIELD 0xff /* for hit-testing */
90 #define DTHT_CHECKBOX 0x200 /* these should end at '00' , to make */
91 #define DTHT_MCPOPUP 0x300 /* & DTHT_DATEFIELD 0 when DATETIME_KeyDown */
92 #define DTHT_GOTFOCUS 0x400 /* tests for date-fields */
94 #define DATETIME_GetInfoPtr(hwnd) ((DATETIME_INFO *)GetWindowLongA (hwnd, 0))
96 static BOOL
DATETIME_SendSimpleNotify (HWND hwnd
, UINT code
);
97 static BOOL
DATETIME_SendDateTimeChangeNotify (HWND hwnd
);
98 extern void MONTHCAL_CopyTime(const SYSTEMTIME
*from
, SYSTEMTIME
*to
);
99 static const char * const days
[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
100 "Thursday", "Friday", "Saturday", NULL
};
101 static const char *allowedformatchars
= {"dhHmMstyX'"};
102 static const int maxrepetition
[] = {4,2,2,2,4,2,2,3,-1,-1};
106 DATETIME_GetSystemTime (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
108 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
109 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
110 SYSTEMTIME
*lprgSysTimeArray
=(SYSTEMTIME
*) lParam
;
112 if (!lParam
) return GDT_NONE
;
114 if ((dwStyle
& DTS_SHOWNONE
) &&
115 (SendMessageA (infoPtr
->hwndCheckbut
, BM_GETCHECK
, 0, 0)))
118 MONTHCAL_CopyTime (&infoPtr
->date
, lprgSysTimeArray
);
125 DATETIME_SetSystemTime (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
127 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
128 SYSTEMTIME
*lprgSysTimeArray
=(SYSTEMTIME
*) lParam
;
130 if (!lParam
) return 0;
132 if (lParam
==GDT_VALID
)
133 MONTHCAL_CopyTime (lprgSysTimeArray
, &infoPtr
->date
);
134 if (lParam
==GDT_NONE
) {
135 infoPtr
->dateValid
=FALSE
;
136 SendMessageA (infoPtr
->hwndCheckbut
, BM_SETCHECK
, 0, 0);
143 DATETIME_GetMonthCalColor (HWND hwnd
, WPARAM wParam
)
145 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
147 return SendMessageA (infoPtr
->hMonthCal
, MCM_GETCOLOR
, wParam
, 0);
152 DATETIME_SetMonthCalColor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
154 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
156 return SendMessageA (infoPtr
->hMonthCal
, MCM_SETCOLOR
, wParam
, lParam
);
160 /* FIXME: need to get way to force font into monthcal structure */
162 DATETIME_GetMonthCal (HWND hwnd
)
164 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
166 return infoPtr
->hMonthCal
;
171 /* FIXME: need to get way to force font into monthcal structure */
174 DATETIME_GetMonthCalFont (HWND hwnd
)
182 DATETIME_SetMonthCalFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
190 Split up a formattxt in actions.
191 See ms documentation for the meaning of the letter codes/'specifiers'.
194 *'dddddd' is handled as 'dddd' plus 'dd'.
195 *unrecognized formats are strings (here given the type DT_STRING;
196 start of the string is encoded in lower bits of DT_STRING.
197 Therefore, 'string' ends finally up as '<show seconds>tring'.
203 DATETIME_UseFormat (DATETIME_INFO
*infoPtr
, const char *formattxt
)
206 int *nrFields
=& infoPtr
->nrFields
;
208 TRACE ("%s\n",formattxt
);
212 infoPtr
->fieldspec
[*nrFields
]=0;
213 len
=strlen(allowedformatchars
);
216 for (i
=0; i
<strlen (formattxt
); i
++) {
217 TRACE ("\n%d %c:",i
, formattxt
[i
]);
218 for (j
=0; j
<len
; j
++) {
219 if (allowedformatchars
[j
]==formattxt
[i
]) {
220 TRACE ("%c[%d,%x]",allowedformatchars
[j
], *nrFields
,
221 infoPtr
->fieldspec
[*nrFields
]);
222 if ((*nrFields
==0) && (infoPtr
->fieldspec
[*nrFields
]==0)) {
223 infoPtr
->fieldspec
[*nrFields
]=(j
<<4) +1;
226 if (infoPtr
->fieldspec
[*nrFields
]>>4!=j
) {
228 infoPtr
->fieldspec
[*nrFields
]=(j
<<4) +1;
231 if ((infoPtr
->fieldspec
[*nrFields
] & 0x0f)==maxrepetition
[j
]) {
233 infoPtr
->fieldspec
[*nrFields
]=(j
<<4) +1;
236 infoPtr
->fieldspec
[*nrFields
]++;
238 } /* if allowedformatchar */
242 /* char is not a specifier: handle char like a string */
244 if ((*nrFields
==0) && (infoPtr
->fieldspec
[*nrFields
]==0)) {
245 infoPtr
->fieldspec
[*nrFields
]=DT_STRING
+k
;
246 infoPtr
->buflen
[*nrFields
]=0;
248 if ((infoPtr
->fieldspec
[*nrFields
] & DT_STRING
)!=DT_STRING
) {
250 infoPtr
->fieldspec
[*nrFields
]=DT_STRING
+k
;
251 infoPtr
->buflen
[*nrFields
]=0;
253 infoPtr
->textbuf
[k
]=formattxt
[i
];
255 infoPtr
->buflen
[*nrFields
]++;
258 if (*nrFields
==infoPtr
->nrFieldsAllocated
) {
259 FIXME ("out of memory; should reallocate. crash ahead.\n");
266 if (infoPtr
->fieldspec
[*nrFields
]!=0) (*nrFields
)++;
271 DATETIME_SetFormat (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
273 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
276 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
278 if (dwStyle
& DTS_LONGDATEFORMAT
)
279 DATETIME_UseFormat (infoPtr
, "dddd, MMMM dd, yyy");
280 else if (dwStyle
& DTS_TIMEFORMAT
)
281 DATETIME_UseFormat (infoPtr
, "h:mm:ss tt");
282 else /* DTS_SHORTDATEFORMAT */
283 DATETIME_UseFormat (infoPtr
, "M/d/yy");
286 DATETIME_UseFormat (infoPtr
, (char *) lParam
);
288 return infoPtr
->nrFields
;
293 DATETIME_SetFormatW (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
299 int len
= lstrlenW ((LPWSTR
) lParam
)+1;
301 buf
= (LPSTR
) COMCTL32_Alloc (len
);
302 lstrcpyWtoA (buf
, (LPWSTR
) lParam
);
303 retval
=DATETIME_SetFormat (hwnd
, 0, (LPARAM
) buf
);
308 return DATETIME_SetFormat (hwnd
, 0, 0);
314 DATETIME_ReturnTxt (DATETIME_INFO
*infoPtr
, int count
, char *result
)
316 SYSTEMTIME date
= infoPtr
->date
;
320 TRACE ("%d,%d\n", infoPtr
->nrFields
, count
);
321 if ((count
>infoPtr
->nrFields
) || (count
<0)) {
322 WARN ("buffer overrun, have %d want %d\n", infoPtr
->nrFields
, count
);
326 if (!infoPtr
->fieldspec
) return;
328 spec
=infoPtr
->fieldspec
[count
];
329 if (spec
& DT_STRING
) {
330 int txtlen
=infoPtr
->buflen
[count
];
332 strncpy (result
, infoPtr
->textbuf
+ (spec
&~ DT_STRING
), txtlen
);
334 TRACE ("arg%d=%x->[%s]\n",count
,infoPtr
->fieldspec
[count
],result
);
344 sprintf (result
,"%d",date
.wDay
);
347 sprintf (result
,"%.2d",date
.wDay
);
350 sprintf (result
,"%.3s",days
[date
.wDayOfWeek
]);
353 strcpy (result
,days
[date
.wDayOfWeek
]);
357 sprintf (result
,"%d",date
.wHour
-12);
359 sprintf (result
,"%d",date
.wHour
);
363 sprintf (result
,"%.2d",date
.wHour
-12);
365 sprintf (result
,"%.2d",date
.wHour
);
368 sprintf (result
,"%d",date
.wHour
);
371 sprintf (result
,"%.2d",date
.wHour
);
374 sprintf (result
,"%d",date
.wSecond
);
377 sprintf (result
,"%.2d",date
.wSecond
);
380 sprintf (result
,"%d",date
.wMinute
);
383 sprintf (result
,"%.2d",date
.wMinute
);
386 sprintf (result
,"%d",date
.wMonth
);
389 sprintf (result
,"%.2d",date
.wMonth
);
392 sprintf (result
,"%.3s",monthtxt
[date
.wMonth
-1]);
395 strcpy (result
,monthtxt
[date
.wMonth
-1]);
405 strcpy (result
,"AM");
407 strcpy (result
,"PM");
410 FIXME ("Not implemented\n");
411 strcpy (result
,"xxx");
414 sprintf (result
,"%d",date
.wYear
-10* (int) floor(date
.wYear
/10));
417 sprintf (result
,"%.2d",date
.wYear
-100* (int) floor(date
.wYear
/100));
420 sprintf (result
,"%d",date
.wYear
);
424 TRACE ("arg%d=%x->[%s]\n",count
,infoPtr
->fieldspec
[count
],result
);
429 DATETIME_IncreaseField (DATETIME_INFO
*infoPtr
, int number
)
431 SYSTEMTIME
*date
= &infoPtr
->date
;
434 TRACE ("%d\n",number
);
435 if ((number
>infoPtr
->nrFields
) || (number
<0)) return;
437 spec
=infoPtr
->fieldspec
[number
];
438 if ((spec
& DTHT_DATEFIELD
)==0) return;
446 if (date
->wDay
>mdays
[date
->wMonth
-1]) date
->wDay
=1;
453 if (date
->wHour
>23) date
->wHour
=0;
458 if (date
->wSecond
>59) date
->wSecond
=0;
463 if (date
->wMinute
>59) date
->wMinute
=0;
470 if (date
->wMonth
>12) date
->wMonth
=1;
471 if (date
->wDay
>mdays
[date
->wMonth
-1])
472 date
->wDay
=mdays
[date
->wMonth
-1];
477 if (date
->wHour
>23) date
->wHour
-=24;
480 FIXME ("Not implemented\n");
493 DATETIME_DecreaseField (DATETIME_INFO
*infoPtr
, int number
)
495 SYSTEMTIME
*date
= & infoPtr
->date
;
498 TRACE ("%d\n",number
);
499 if ((number
>infoPtr
->nrFields
) || (number
<0)) return;
501 spec
= infoPtr
->fieldspec
[number
];
502 if ((spec
& DTHT_DATEFIELD
)==0) return;
512 if (date
->wDay
<1) date
->wDay
=mdays
[date
->wMonth
-1];
545 if (date
->wDay
>mdays
[date
->wMonth
-1])
546 date
->wDay
=mdays
[date
->wMonth
-1];
556 FIXME ("Not implemented\n");
569 DATETIME_ResetFieldDown (DATETIME_INFO
*infoPtr
, int number
)
571 SYSTEMTIME
*date
= &infoPtr
->date
;
574 TRACE ("%d\n",number
);
575 if ((number
>infoPtr
->nrFields
) || (number
<0)) return;
577 spec
= infoPtr
->fieldspec
[number
];
578 if ((spec
& DTHT_DATEFIELD
)==0) return;
610 FIXME ("Not implemented\n");
614 /* FYI: On 9/14/1752 the calender changed and England and the American */
615 /* colonies changed to the Gregorian calender. This change involved */
616 /* having September 14th following September 2nd. So no date algorithms */
617 /* work before that date. */
622 date
->wDay
= 14; /* overactive ms-programmers..*/
632 DATETIME_ResetFieldUp (DATETIME_INFO
*infoPtr
, int number
)
634 SYSTEMTIME
*date
= & infoPtr
->date
;
637 if ((number
>infoPtr
->nrFields
) || (number
<0)) return;
639 spec
=infoPtr
->fieldspec
[number
];
640 if ((spec
& DTHT_DATEFIELD
)==0) return;
647 date
->wDay
=mdays
[date
->wMonth
-1];
671 FIXME ("Not implemented\n");
676 date
->wYear
=9999; /* Y10K problem? naaah. */
683 static void DATETIME_Refresh (HWND hwnd
, HDC hdc
)
686 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
689 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
690 RECT
*rcDraw
= &infoPtr
->rcDraw
;
691 RECT
*rcClient
= &infoPtr
->rcClient
;
692 RECT
*calbutton
= &infoPtr
->calbutton
;
693 RECT
*checkbox
= &infoPtr
->checkbox
;
696 COLORREF oldBk
, oldTextColor
;
698 /* draw control edge */
699 hbr
= CreateSolidBrush(RGB(255, 255, 255));
700 FillRect(hdc
, rcClient
, hbr
);
701 DrawEdge(hdc
, rcClient
, EDGE_SUNKEN
, BF_RECT
);
704 if (infoPtr
->dateValid
) {
707 oldFont
= SelectObject (hdc
, infoPtr
->hFont
);
709 DATETIME_ReturnTxt (infoPtr
, 0, txt
);
710 GetTextExtentPoint32A (hdc
, txt
, strlen (txt
), &size
);
711 rcDraw
->bottom
= size
.cy
+2;
713 if (dwStyle
& DTS_SHOWNONE
) checkbox
->right
= 18;
715 prevright
= checkbox
->right
;
717 for (i
=0; i
<infoPtr
->nrFields
; i
++) {
718 DATETIME_ReturnTxt (infoPtr
, i
, txt
);
719 GetTextExtentPoint32A (hdc
, txt
, strlen (txt
), &size
);
720 field
= & infoPtr
->fieldRect
[i
];
721 field
->left
= prevright
;
722 field
->right
= prevright
+size
.cx
;
723 field
->top
= rcDraw
->top
;
724 field
->bottom
= rcDraw
->bottom
;
725 prevright
= field
->right
;
727 if ((infoPtr
->haveFocus
) && (i
==infoPtr
->select
)) {
728 hbr
= CreateSolidBrush (GetSysColor (COLOR_ACTIVECAPTION
));
729 FillRect(hdc
, field
, hbr
);
730 oldBk
= SetBkColor (hdc
, GetSysColor(COLOR_ACTIVECAPTION
));
731 oldTextColor
= SetTextColor (hdc
, GetSysColor(COLOR_WINDOW
));
733 DrawTextA ( hdc
, txt
, strlen(txt
), field
,
734 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
735 SetBkColor (hdc
, oldBk
);
736 SetTextColor (hdc
, oldTextColor
);
739 DrawTextA ( hdc
, txt
, strlen(txt
), field
,
740 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
743 SelectObject (hdc
, oldFont
);
746 if (!(dwStyle
& DTS_UPDOWN
)) {
747 DrawFrameControl(hdc
, calbutton
, DFC_SCROLL
,
748 DFCS_SCROLLDOWN
| (infoPtr
->bCalDepressed
? DFCS_PUSHED
: 0) |
749 (dwStyle
& WS_DISABLED
? DFCS_INACTIVE
: 0) );
755 DATETIME_HitTest (HWND hwnd
, DATETIME_INFO
*infoPtr
, POINT pt
)
759 TRACE ("%ld, %ld\n",pt
.x
,pt
.y
);
762 if (PtInRect (&infoPtr
->calbutton
, pt
))
763 {retval
= DTHT_MCPOPUP
; TRACE("Hit in calbutton(DTHT_MCPOPUP)\n"); goto done
; }
764 if (PtInRect (&infoPtr
->checkbox
, pt
))
765 {retval
= DTHT_CHECKBOX
; TRACE("Hit in checkbox(DTHT_CHECKBOX)\n"); goto done
; }
767 for (i
=0; i
<infoPtr
->nrFields
; i
++) {
768 if (PtInRect (&infoPtr
->fieldRect
[i
], pt
)) {
770 TRACE("Hit in date text in field %d\n", i
);
781 DATETIME_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
783 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
784 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
790 old
= infoPtr
->select
;
791 pt
.x
= (INT
)LOWORD(lParam
);
792 pt
.y
= (INT
)HIWORD(lParam
);
794 new = DATETIME_HitTest (hwnd
, infoPtr
, pt
);
796 /* FIXME: might be conditions where we don't want to update infoPtr->select */
797 infoPtr
->select
= new;
799 if (infoPtr
->select
!= old
) {
800 infoPtr
->haveFocus
= DTHT_GOTFOCUS
;
803 if (infoPtr
->select
== DTHT_MCPOPUP
) {
804 /* FIXME: button actually is only depressed during dropdown of the */
805 /* calender control and when the mouse is over the button window */
806 infoPtr
->bCalDepressed
= TRUE
;
808 /* recalculate the position of the monthcal popup */
809 if(dwStyle
& DTS_RIGHTALIGN
)
810 infoPtr
->monthcal_pos
.x
= infoPtr
->rcClient
.right
- ((infoPtr
->calbutton
.right
-
811 infoPtr
->calbutton
.left
) + 145);
813 infoPtr
->monthcal_pos
.x
= 8;
815 infoPtr
->monthcal_pos
.y
= infoPtr
->rcClient
.bottom
;
816 ClientToScreen (hwnd
, &(infoPtr
->monthcal_pos
));
817 SetWindowPos(infoPtr
->hMonthCal
, 0, infoPtr
->monthcal_pos
.x
,
818 infoPtr
->monthcal_pos
.y
, 145, 150, 0);
820 if(IsWindowVisible(infoPtr
->hMonthCal
))
821 ShowWindow(infoPtr
->hMonthCal
, SW_HIDE
);
823 ShowWindow(infoPtr
->hMonthCal
, SW_SHOW
);
825 TRACE ("dt:%x mc:%x mc parent:%x, desktop:%x, mcpp:%x\n",
826 hwnd
,infoPtr
->hMonthCal
,
827 GetParent (infoPtr
->hMonthCal
),
829 GetParent (GetParent (infoPtr
->hMonthCal
)));
830 DATETIME_SendSimpleNotify (hwnd
, DTN_DROPDOWN
);
833 InvalidateRect(hwnd
, NULL
, FALSE
);
840 DATETIME_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
842 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
846 if(infoPtr
->bCalDepressed
== TRUE
) {
847 infoPtr
->bCalDepressed
= FALSE
;
848 RedrawWindow(hwnd
, &(infoPtr
->calbutton
), 0, RDW_ERASE
|RDW_INVALIDATE
);
856 DATETIME_Paint (HWND hwnd
, WPARAM wParam
)
861 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
862 DATETIME_Refresh (hwnd
, hdc
);
864 EndPaint (hwnd
, &ps
);
870 DATETIME_ParentNotify (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
872 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
873 LPNMHDR lpnmh
= (LPNMHDR
) lParam
;
875 TRACE ("%x,%lx\n",wParam
, lParam
);
876 TRACE ("Got notification %x from %x\n", lpnmh
->code
, lpnmh
->hwndFrom
);
877 TRACE ("info: %x %x %x\n",hwnd
,infoPtr
->hMonthCal
,infoPtr
->hUpdown
);
883 DATETIME_Notify (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
886 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
887 LPNMHDR lpnmh
= (LPNMHDR
) lParam
;
889 TRACE ("%x,%lx\n",wParam
, lParam
);
890 TRACE ("Got notification %x from %x\n", lpnmh
->code
, lpnmh
->hwndFrom
);
891 TRACE ("info: %x %x %x\n",hwnd
,infoPtr
->hMonthCal
,infoPtr
->hUpdown
);
897 DATETIME_KeyDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
899 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
902 TRACE("%x %lx %x\n",wParam
, lParam
, infoPtr
->select
);
904 FieldNum
= infoPtr
->select
& DTHT_DATEFIELD
;
906 if (!(infoPtr
->haveFocus
)) return 0;
907 if ((FieldNum
==0) && (infoPtr
->select
)) return 0;
909 if (infoPtr
->select
& FORMATCALLMASK
) {
910 FIXME ("Callbacks not implemented yet\n");
916 DATETIME_IncreaseField (infoPtr
,FieldNum
);
917 DATETIME_SendDateTimeChangeNotify (hwnd
);
921 DATETIME_DecreaseField (infoPtr
,FieldNum
);
922 DATETIME_SendDateTimeChangeNotify (hwnd
);
925 DATETIME_ResetFieldDown (infoPtr
,FieldNum
);
926 DATETIME_SendDateTimeChangeNotify (hwnd
);
929 DATETIME_ResetFieldUp(infoPtr
,FieldNum
);
930 DATETIME_SendDateTimeChangeNotify (hwnd
);
934 if (infoPtr
->select
==0) {
935 infoPtr
->select
= infoPtr
->nrFields
- 1;
940 while ((infoPtr
->fieldspec
[infoPtr
->select
] & DT_STRING
) && (wrap
<2));
945 if (infoPtr
->select
==infoPtr
->nrFields
) {
950 while ((infoPtr
->fieldspec
[infoPtr
->select
] & DT_STRING
) && (wrap
<2));
954 InvalidateRect(hwnd
, NULL
, FALSE
);
961 DATETIME_KillFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
963 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
967 if (infoPtr
->haveFocus
) {
968 DATETIME_SendSimpleNotify (hwnd
, NM_KILLFOCUS
);
969 infoPtr
->haveFocus
= 0;
972 InvalidateRect (hwnd
, NULL
, TRUE
);
979 DATETIME_SetFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
981 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
985 if (infoPtr
->haveFocus
==0) {
986 DATETIME_SendSimpleNotify (hwnd
, NM_SETFOCUS
);
987 infoPtr
->haveFocus
= DTHT_GOTFOCUS
;
990 InvalidateRect(hwnd
, NULL
, FALSE
);
997 DATETIME_SendDateTimeChangeNotify (HWND hwnd
)
1000 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
1001 NMDATETIMECHANGE dtdtc
;
1004 dtdtc
.nmhdr
.hwndFrom
= hwnd
;
1005 dtdtc
.nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
1006 dtdtc
.nmhdr
.code
= DTN_DATETIMECHANGE
;
1008 if ((GetWindowLongA (hwnd
, GWL_STYLE
) & DTS_SHOWNONE
))
1009 dtdtc
.dwFlags
= GDT_NONE
;
1011 dtdtc
.dwFlags
= GDT_VALID
;
1013 MONTHCAL_CopyTime (&infoPtr
->date
, &dtdtc
.st
);
1014 return (BOOL
) SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1015 (WPARAM
)dtdtc
.nmhdr
.idFrom
, (LPARAM
)&dtdtc
);
1020 DATETIME_SendSimpleNotify (HWND hwnd
, UINT code
)
1025 nmhdr
.hwndFrom
= hwnd
;
1026 nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
1029 return (BOOL
) SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1030 (WPARAM
)nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
1034 DATETIME_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1036 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr(hwnd
);
1037 DWORD dwStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1040 infoPtr
->rcClient
.bottom
= HIWORD(lParam
);
1041 infoPtr
->rcClient
.right
= LOWORD(lParam
);
1043 TRACE("Height=%d, Width=%d\n", infoPtr
->rcClient
.bottom
, infoPtr
->rcClient
.right
);
1045 /* use DrawEdge to adjust the size of rcEdge to get rcDraw */
1046 memcpy((&infoPtr
->rcDraw
), (&infoPtr
->rcClient
), sizeof(infoPtr
->rcDraw
));
1048 DrawEdge((HDC
)NULL
, &(infoPtr
->rcDraw
), EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
1050 /* set the size of the button that drops the calender down */
1051 /* FIXME: account for style that allows button on left side */
1052 infoPtr
->calbutton
.top
= infoPtr
->rcDraw
.top
;
1053 infoPtr
->calbutton
.bottom
= infoPtr
->rcDraw
.bottom
;
1054 infoPtr
->calbutton
.left
= infoPtr
->rcDraw
.right
-15;
1055 infoPtr
->calbutton
.right
= infoPtr
->rcDraw
.right
;
1057 /* set enable/disable button size for show none style being enabled */
1058 /* FIXME: these dimensions are completely incorrect */
1059 infoPtr
->checkbox
.top
= infoPtr
->rcDraw
.top
;
1060 infoPtr
->checkbox
.bottom
= infoPtr
->rcDraw
.bottom
;
1061 infoPtr
->checkbox
.left
= infoPtr
->rcDraw
.left
;
1062 infoPtr
->checkbox
.right
= infoPtr
->rcDraw
.left
+ 10;
1064 /* update the position of the monthcal control */
1065 if(dwStyle
& DTS_RIGHTALIGN
)
1066 infoPtr
->monthcal_pos
.x
= infoPtr
->rcClient
.right
- ((infoPtr
->calbutton
.right
-
1067 infoPtr
->calbutton
.left
) + 145);
1069 infoPtr
->monthcal_pos
.x
= 8;
1071 infoPtr
->monthcal_pos
.y
= infoPtr
->rcClient
.bottom
;
1072 ClientToScreen (hwnd
, &(infoPtr
->monthcal_pos
));
1073 SetWindowPos(infoPtr
->hMonthCal
, 0, infoPtr
->monthcal_pos
.x
,
1074 infoPtr
->monthcal_pos
.y
,
1077 InvalidateRect(hwnd
, NULL
, FALSE
);
1084 DATETIME_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1086 DATETIME_INFO
*infoPtr
;
1087 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
1089 /* allocate memory for info structure */
1090 infoPtr
= (DATETIME_INFO
*)COMCTL32_Alloc (sizeof(DATETIME_INFO
));
1091 if (infoPtr
== NULL
) {
1092 ERR("could not allocate info memory!\n");
1096 SetWindowLongA (hwnd
, 0, (DWORD
)infoPtr
);
1098 if (dwStyle
& DTS_SHOWNONE
) {
1099 infoPtr
->hwndCheckbut
=CreateWindowExA (0,"button", 0,
1100 WS_CHILD
| WS_VISIBLE
| BS_AUTOCHECKBOX
,
1103 0, GetWindowLongA (hwnd
, GWL_HINSTANCE
), 0);
1104 SendMessageA (infoPtr
->hwndCheckbut
, BM_SETCHECK
, 1, 0);
1107 if (dwStyle
& DTS_UPDOWN
) {
1108 infoPtr
->hUpdown
=CreateUpDownControl (
1109 WS_CHILD
| WS_BORDER
| WS_VISIBLE
,
1112 UD_MAXVAL
, UD_MINVAL
, 0);
1115 infoPtr
->fieldspec
= (int *) COMCTL32_Alloc (32*sizeof(int));
1116 infoPtr
->fieldRect
= (RECT
*) COMCTL32_Alloc (32*sizeof(RECT
));
1117 infoPtr
->buflen
= (int *) COMCTL32_Alloc (32*sizeof(int));
1118 infoPtr
->nrFieldsAllocated
= 32;
1120 DATETIME_SetFormat (hwnd
, 0, 0);
1122 /* create the monthcal control */
1123 infoPtr
->hMonthCal
= CreateWindowExA (0,"SysMonthCal32", 0,
1124 WS_BORDER
| WS_POPUP
| WS_CLIPSIBLINGS
,
1129 /* initialize info structure */
1130 GetSystemTime (&infoPtr
->date
);
1131 infoPtr
->dateValid
= TRUE
;
1132 infoPtr
->hFont
= GetStockObject(DEFAULT_GUI_FONT
);
1138 DATETIME_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1140 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
1142 COMCTL32_Free (infoPtr
);
1147 static LRESULT WINAPI
1148 DATETIME_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1153 case DTM_GETSYSTEMTIME
:
1154 DATETIME_GetSystemTime (hwnd
, wParam
, lParam
);
1156 case DTM_SETSYSTEMTIME
:
1157 DATETIME_SetSystemTime (hwnd
, wParam
, lParam
);
1160 FIXME("Unimplemented msg DTM_GETRANGE\n");
1164 FIXME("Unimplemented msg DTM_SETRANGE\n");
1167 case DTM_SETFORMATA
:
1168 return DATETIME_SetFormat (hwnd
, wParam
, lParam
);
1170 case DTM_SETFORMATW
:
1171 return DATETIME_SetFormatW (hwnd
, wParam
, lParam
);
1173 case DTM_SETMCCOLOR
:
1174 return DATETIME_SetMonthCalColor (hwnd
, wParam
, lParam
);
1176 case DTM_GETMCCOLOR
:
1177 return DATETIME_GetMonthCalColor (hwnd
, wParam
);
1179 case DTM_GETMONTHCAL
:
1180 return DATETIME_GetMonthCal (hwnd
);
1183 return DATETIME_SetMonthCalFont (hwnd
, wParam
, lParam
);
1186 return DATETIME_GetMonthCalFont (hwnd
);
1188 case WM_PARENTNOTIFY
:
1189 return DATETIME_ParentNotify (hwnd
, wParam
, lParam
);
1192 return DATETIME_Notify (hwnd
, wParam
, lParam
);
1195 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1198 return DATETIME_Paint (hwnd
, wParam
);
1201 return DATETIME_KeyDown (hwnd
, wParam
, lParam
);
1204 return DATETIME_KillFocus (hwnd
, wParam
, lParam
);
1207 return DATETIME_SetFocus (hwnd
, wParam
, lParam
);
1210 return DATETIME_Size (hwnd
, wParam
, lParam
);
1212 case WM_LBUTTONDOWN
:
1213 return DATETIME_LButtonDown (hwnd
, wParam
, lParam
);
1216 return DATETIME_LButtonUp (hwnd
, wParam
, lParam
);
1219 return DATETIME_Create (hwnd
, wParam
, lParam
);
1222 return DATETIME_Destroy (hwnd
, wParam
, lParam
);
1225 if (uMsg
>= WM_USER
)
1226 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
1227 uMsg
, wParam
, lParam
);
1228 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
1235 DATETIME_Register (void)
1239 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
1240 wndClass
.style
= CS_GLOBALCLASS
;
1241 wndClass
.lpfnWndProc
= (WNDPROC
)DATETIME_WindowProc
;
1242 wndClass
.cbClsExtra
= 0;
1243 wndClass
.cbWndExtra
= sizeof(DATETIME_INFO
*);
1244 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
1245 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1246 wndClass
.lpszClassName
= DATETIMEPICK_CLASSA
;
1248 RegisterClassA (&wndClass
);
1253 DATETIME_Unregister (void)
1255 UnregisterClassA (DATETIMEPICK_CLASSA
, (HINSTANCE
)NULL
);