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 int MONTHCAL_MonthLength(int month
, int year
);
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 *allowedformatchars
= {"dhHmMstyX'"};
100 static const int maxrepetition
[] = {4,2,2,2,4,2,2,3,-1,-1};
104 DATETIME_GetSystemTime (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
106 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
107 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
108 SYSTEMTIME
*lprgSysTimeArray
=(SYSTEMTIME
*) lParam
;
110 TRACE("%04x %08lx\n",wParam
,lParam
);
111 if (!lParam
) return GDT_NONE
;
113 if ((dwStyle
& DTS_SHOWNONE
) &&
114 (SendMessageA (infoPtr
->hwndCheckbut
, BM_GETCHECK
, 0, 0)))
117 MONTHCAL_CopyTime (&infoPtr
->date
, lprgSysTimeArray
);
124 DATETIME_SetSystemTime (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
126 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
127 SYSTEMTIME
*lprgSysTimeArray
=(SYSTEMTIME
*) lParam
;
129 TRACE("%04x %08lx\n",wParam
,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 TRACE("%04x\n",wParam
);
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 TRACE("%04x %08lx\n",wParam
,lParam
);
158 return SendMessageA (infoPtr
->hMonthCal
, MCM_SETCOLOR
, wParam
, lParam
);
162 /* FIXME: need to get way to force font into monthcal structure */
164 DATETIME_GetMonthCal (HWND hwnd
)
166 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
169 return infoPtr
->hMonthCal
;
174 /* FIXME: need to get way to force font into monthcal structure */
177 DATETIME_GetMonthCalFont (HWND hwnd
)
186 DATETIME_SetMonthCalFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
189 TRACE("%04x %08lx\n",wParam
,lParam
);
195 Split up a formattxt in actions.
196 See ms documentation for the meaning of the letter codes/'specifiers'.
199 *'dddddd' is handled as 'dddd' plus 'dd'.
200 *unrecognized formats are strings (here given the type DT_STRING;
201 start of the string is encoded in lower bits of DT_STRING.
202 Therefore, 'string' ends finally up as '<show seconds>tring'.
208 DATETIME_UseFormat (DATETIME_INFO
*infoPtr
, const char *formattxt
)
211 int *nrFields
=& infoPtr
->nrFields
;
213 TRACE ("%s\n",formattxt
);
217 infoPtr
->fieldspec
[*nrFields
]=0;
218 len
=strlen(allowedformatchars
);
221 for (i
=0; i
<strlen (formattxt
); i
++) {
222 TRACE ("\n%d %c:",i
, formattxt
[i
]);
223 for (j
=0; j
<len
; j
++) {
224 if (allowedformatchars
[j
]==formattxt
[i
]) {
225 TRACE ("%c[%d,%x]",allowedformatchars
[j
], *nrFields
,
226 infoPtr
->fieldspec
[*nrFields
]);
227 if ((*nrFields
==0) && (infoPtr
->fieldspec
[*nrFields
]==0)) {
228 infoPtr
->fieldspec
[*nrFields
]=(j
<<4) +1;
231 if (infoPtr
->fieldspec
[*nrFields
]>>4!=j
) {
233 infoPtr
->fieldspec
[*nrFields
]=(j
<<4) +1;
236 if ((infoPtr
->fieldspec
[*nrFields
] & 0x0f)==maxrepetition
[j
]) {
238 infoPtr
->fieldspec
[*nrFields
]=(j
<<4) +1;
241 infoPtr
->fieldspec
[*nrFields
]++;
243 } /* if allowedformatchar */
247 /* char is not a specifier: handle char like a string */
249 if ((*nrFields
==0) && (infoPtr
->fieldspec
[*nrFields
]==0)) {
250 infoPtr
->fieldspec
[*nrFields
]=DT_STRING
+k
;
251 infoPtr
->buflen
[*nrFields
]=0;
253 if ((infoPtr
->fieldspec
[*nrFields
] & DT_STRING
)!=DT_STRING
) {
255 infoPtr
->fieldspec
[*nrFields
]=DT_STRING
+k
;
256 infoPtr
->buflen
[*nrFields
]=0;
258 infoPtr
->textbuf
[k
]=formattxt
[i
];
260 infoPtr
->buflen
[*nrFields
]++;
263 if (*nrFields
==infoPtr
->nrFieldsAllocated
) {
264 FIXME ("out of memory; should reallocate. crash ahead.\n");
271 if (infoPtr
->fieldspec
[*nrFields
]!=0) (*nrFields
)++;
276 DATETIME_SetFormat (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
278 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
282 TRACE("%04x %08lx\n",wParam
,lParam
);
284 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
286 if (dwStyle
& DTS_LONGDATEFORMAT
)
287 format_item
=LOCALE_SLONGDATE
;
288 else if (dwStyle
& DTS_TIMEFORMAT
)
289 format_item
=LOCALE_STIMEFORMAT
;
290 else /* DTS_SHORTDATEFORMAT */
291 format_item
=LOCALE_SSHORTDATE
;
292 GetLocaleInfoA( GetSystemDefaultLCID(), format_item
,format_buf
,sizeof(format_buf
));
293 DATETIME_UseFormat (infoPtr
, format_buf
);
296 DATETIME_UseFormat (infoPtr
, (char *) lParam
);
298 return infoPtr
->nrFields
;
303 DATETIME_SetFormatW (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
306 TRACE("%04x %08lx\n",wParam
,lParam
);
310 int len
= lstrlenW ((LPWSTR
) lParam
)+1;
312 buf
= (LPSTR
) COMCTL32_Alloc (len
);
313 lstrcpyWtoA (buf
, (LPWSTR
) lParam
);
314 retval
=DATETIME_SetFormat (hwnd
, 0, (LPARAM
) buf
);
319 return DATETIME_SetFormat (hwnd
, 0, 0);
325 DATETIME_ReturnTxt (DATETIME_INFO
*infoPtr
, int count
, char *result
)
327 SYSTEMTIME date
= infoPtr
->date
;
332 TRACE ("%d,%d\n", infoPtr
->nrFields
, count
);
333 if ((count
>infoPtr
->nrFields
) || (count
<0)) {
334 WARN ("buffer overrun, have %d want %d\n", infoPtr
->nrFields
, count
);
338 if (!infoPtr
->fieldspec
) return;
340 spec
=infoPtr
->fieldspec
[count
];
341 if (spec
& DT_STRING
) {
342 int txtlen
=infoPtr
->buflen
[count
];
344 strncpy (result
, infoPtr
->textbuf
+ (spec
&~ DT_STRING
), txtlen
);
346 TRACE ("arg%d=%x->[%s]\n",count
,infoPtr
->fieldspec
[count
],result
);
356 sprintf (result
,"%d",date
.wDay
);
359 sprintf (result
,"%.2d",date
.wDay
);
362 GetLocaleInfoA( LOCALE_USER_DEFAULT
, LOCALE_SABBREVDAYNAME1
+(date
.wDayOfWeek
+6)%7,
364 /*sprintf (result,"%.3s",days[date.wDayOfWeek]);*/
367 GetLocaleInfoA( LOCALE_USER_DEFAULT
,LOCALE_SDAYNAME1
+ (date
.wDayOfWeek
+6)%7,
368 buffer
,sizeof(buffer
));
369 strcpy (result
,buffer
);
373 sprintf (result
,"%d",date
.wHour
-12);
375 sprintf (result
,"%d",date
.wHour
);
379 sprintf (result
,"%.2d",date
.wHour
-12);
381 sprintf (result
,"%.2d",date
.wHour
);
384 sprintf (result
,"%d",date
.wHour
);
387 sprintf (result
,"%.2d",date
.wHour
);
390 sprintf (result
,"%d",date
.wSecond
);
393 sprintf (result
,"%.2d",date
.wSecond
);
396 sprintf (result
,"%d",date
.wMinute
);
399 sprintf (result
,"%.2d",date
.wMinute
);
402 sprintf (result
,"%d",date
.wMonth
);
405 sprintf (result
,"%.2d",date
.wMonth
);
408 GetLocaleInfoA( GetSystemDefaultLCID(),LOCALE_SMONTHNAME1
+date
.wMonth
-1,
409 buffer
,sizeof(buffer
));
410 sprintf (result
,"%.3s",buffer
);
413 GetLocaleInfoA( GetSystemDefaultLCID(),LOCALE_SMONTHNAME1
+date
.wMonth
-1,
414 result
,sizeof(result
));
424 strcpy (result
,"AM");
426 strcpy (result
,"PM");
429 FIXME ("Not implemented\n");
430 strcpy (result
,"xxx");
433 sprintf (result
,"%d",date
.wYear
-10* (int) floor(date
.wYear
/10));
436 sprintf (result
,"%.2d",date
.wYear
-100* (int) floor(date
.wYear
/100));
439 sprintf (result
,"%d",date
.wYear
);
443 TRACE ("arg%d=%x->[%s]\n",count
,infoPtr
->fieldspec
[count
],result
);
448 DATETIME_IncreaseField (DATETIME_INFO
*infoPtr
, int number
)
450 SYSTEMTIME
*date
= &infoPtr
->date
;
453 TRACE ("%d\n",number
);
454 if ((number
>infoPtr
->nrFields
) || (number
<0)) return;
456 spec
=infoPtr
->fieldspec
[number
];
457 if ((spec
& DTHT_DATEFIELD
)==0) return;
465 if (date
->wDay
>MONTHCAL_MonthLength(date
->wMonth
,date
->wYear
))
473 if (date
->wHour
>23) date
->wHour
=0;
478 if (date
->wSecond
>59) date
->wSecond
=0;
483 if (date
->wMinute
>59) date
->wMinute
=0;
490 if (date
->wMonth
>12) date
->wMonth
=1;
491 if (date
->wDay
>MONTHCAL_MonthLength(date
->wMonth
,date
->wYear
))
492 date
->wDay
=MONTHCAL_MonthLength(date
->wMonth
,date
->wYear
);
497 if (date
->wHour
>23) date
->wHour
-=24;
500 FIXME ("Not implemented\n");
513 DATETIME_DecreaseField (DATETIME_INFO
*infoPtr
, int number
)
515 SYSTEMTIME
*date
= & infoPtr
->date
;
518 TRACE ("%d\n",number
);
519 if ((number
>infoPtr
->nrFields
) || (number
<0)) return;
521 spec
= infoPtr
->fieldspec
[number
];
522 if ((spec
& DTHT_DATEFIELD
)==0) return;
533 date
->wDay
=MONTHCAL_MonthLength(date
->wMonth
,date
->wYear
);
566 if (date
->wDay
>MONTHCAL_MonthLength(date
->wMonth
,date
->wYear
))
567 date
->wDay
=MONTHCAL_MonthLength(date
->wMonth
,date
->wYear
);
577 FIXME ("Not implemented\n");
590 DATETIME_ResetFieldDown (DATETIME_INFO
*infoPtr
, int number
)
592 SYSTEMTIME
*date
= &infoPtr
->date
;
595 TRACE ("%d\n",number
);
596 if ((number
>infoPtr
->nrFields
) || (number
<0)) return;
598 spec
= infoPtr
->fieldspec
[number
];
599 if ((spec
& DTHT_DATEFIELD
)==0) return;
631 FIXME ("Not implemented\n");
635 /* FYI: On 9/14/1752 the calender changed and England and the American */
636 /* colonies changed to the Gregorian calender. This change involved */
637 /* having September 14th following September 2nd. So no date algorithms */
638 /* work before that date. */
643 date
->wDay
= 14; /* overactive ms-programmers..*/
653 DATETIME_ResetFieldUp (DATETIME_INFO
*infoPtr
, int number
)
655 SYSTEMTIME
*date
= & infoPtr
->date
;
658 TRACE("%d \n",number
);
659 if ((number
>infoPtr
->nrFields
) || (number
<0)) return;
661 spec
=infoPtr
->fieldspec
[number
];
662 if ((spec
& DTHT_DATEFIELD
)==0) return;
669 date
->wDay
=MONTHCAL_MonthLength(date
->wMonth
,date
->wYear
);
693 FIXME ("Not implemented\n");
698 date
->wYear
=9999; /* Y10K problem? naaah. */
705 static void DATETIME_Refresh (HWND hwnd
, HDC hdc
)
708 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
711 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
712 RECT
*rcDraw
= &infoPtr
->rcDraw
;
713 RECT
*rcClient
= &infoPtr
->rcClient
;
714 RECT
*calbutton
= &infoPtr
->calbutton
;
715 RECT
*checkbox
= &infoPtr
->checkbox
;
718 COLORREF oldBk
, oldTextColor
;
720 /* draw control edge */
722 hbr
= CreateSolidBrush(RGB(255, 255, 255));
723 FillRect(hdc
, rcClient
, hbr
);
724 DrawEdge(hdc
, rcClient
, EDGE_SUNKEN
, BF_RECT
);
727 if (infoPtr
->dateValid
) {
730 oldFont
= SelectObject (hdc
, infoPtr
->hFont
);
732 DATETIME_ReturnTxt (infoPtr
, 0, txt
);
733 GetTextExtentPoint32A (hdc
, txt
, strlen (txt
), &size
);
734 rcDraw
->bottom
= size
.cy
+2;
736 if (dwStyle
& DTS_SHOWNONE
) checkbox
->right
= 18;
738 prevright
= checkbox
->right
;
740 for (i
=0; i
<infoPtr
->nrFields
; i
++) {
741 DATETIME_ReturnTxt (infoPtr
, i
, txt
);
742 GetTextExtentPoint32A (hdc
, txt
, strlen (txt
), &size
);
743 field
= & infoPtr
->fieldRect
[i
];
744 field
->left
= prevright
;
745 field
->right
= prevright
+size
.cx
;
746 field
->top
= rcDraw
->top
;
747 field
->bottom
= rcDraw
->bottom
;
748 prevright
= field
->right
;
750 if ((infoPtr
->haveFocus
) && (i
==infoPtr
->select
)) {
751 hbr
= CreateSolidBrush (GetSysColor (COLOR_ACTIVECAPTION
));
752 FillRect(hdc
, field
, hbr
);
753 oldBk
= SetBkColor (hdc
, GetSysColor(COLOR_ACTIVECAPTION
));
754 oldTextColor
= SetTextColor (hdc
, GetSysColor(COLOR_WINDOW
));
756 DrawTextA ( hdc
, txt
, strlen(txt
), field
,
757 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
758 SetBkColor (hdc
, oldBk
);
759 SetTextColor (hdc
, oldTextColor
);
762 DrawTextA ( hdc
, txt
, strlen(txt
), field
,
763 DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
);
766 SelectObject (hdc
, oldFont
);
769 if (!(dwStyle
& DTS_UPDOWN
)) {
770 DrawFrameControl(hdc
, calbutton
, DFC_SCROLL
,
771 DFCS_SCROLLDOWN
| (infoPtr
->bCalDepressed
? DFCS_PUSHED
: 0) |
772 (dwStyle
& WS_DISABLED
? DFCS_INACTIVE
: 0) );
778 DATETIME_HitTest (HWND hwnd
, DATETIME_INFO
*infoPtr
, POINT pt
)
782 TRACE ("%ld, %ld\n",pt
.x
,pt
.y
);
785 if (PtInRect (&infoPtr
->calbutton
, pt
))
786 {retval
= DTHT_MCPOPUP
; TRACE("Hit in calbutton(DTHT_MCPOPUP)\n"); goto done
; }
787 if (PtInRect (&infoPtr
->checkbox
, pt
))
788 {retval
= DTHT_CHECKBOX
; TRACE("Hit in checkbox(DTHT_CHECKBOX)\n"); goto done
; }
790 for (i
=0; i
<infoPtr
->nrFields
; i
++) {
791 if (PtInRect (&infoPtr
->fieldRect
[i
], pt
)) {
793 TRACE("Hit in date text in field %d\n", i
);
804 DATETIME_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
806 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
807 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
813 old
= infoPtr
->select
;
814 pt
.x
= (INT
)LOWORD(lParam
);
815 pt
.y
= (INT
)HIWORD(lParam
);
817 new = DATETIME_HitTest (hwnd
, infoPtr
, pt
);
819 /* FIXME: might be conditions where we don't want to update infoPtr->select */
820 infoPtr
->select
= new;
822 if (infoPtr
->select
!= old
) {
823 infoPtr
->haveFocus
= DTHT_GOTFOCUS
;
826 if (infoPtr
->select
== DTHT_MCPOPUP
) {
827 /* FIXME: button actually is only depressed during dropdown of the */
828 /* calender control and when the mouse is over the button window */
829 infoPtr
->bCalDepressed
= TRUE
;
831 /* recalculate the position of the monthcal popup */
832 if(dwStyle
& DTS_RIGHTALIGN
)
833 infoPtr
->monthcal_pos
.x
= infoPtr
->rcClient
.right
- ((infoPtr
->calbutton
.right
-
834 infoPtr
->calbutton
.left
) + 145);
836 infoPtr
->monthcal_pos
.x
= 8;
838 infoPtr
->monthcal_pos
.y
= infoPtr
->rcClient
.bottom
;
839 ClientToScreen (hwnd
, &(infoPtr
->monthcal_pos
));
840 SetWindowPos(infoPtr
->hMonthCal
, 0, infoPtr
->monthcal_pos
.x
,
841 infoPtr
->monthcal_pos
.y
, 145, 150, 0);
843 if(IsWindowVisible(infoPtr
->hMonthCal
))
844 ShowWindow(infoPtr
->hMonthCal
, SW_HIDE
);
846 ShowWindow(infoPtr
->hMonthCal
, SW_SHOW
);
848 TRACE ("dt:%x mc:%x mc parent:%x, desktop:%x, mcpp:%x\n",
849 hwnd
,infoPtr
->hMonthCal
,
850 GetParent (infoPtr
->hMonthCal
),
852 GetParent (GetParent (infoPtr
->hMonthCal
)));
853 DATETIME_SendSimpleNotify (hwnd
, DTN_DROPDOWN
);
856 InvalidateRect(hwnd
, NULL
, FALSE
);
863 DATETIME_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
865 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
869 if(infoPtr
->bCalDepressed
== TRUE
) {
870 infoPtr
->bCalDepressed
= FALSE
;
871 InvalidateRect(hwnd
, &(infoPtr
->calbutton
), TRUE
);
879 DATETIME_Paint (HWND hwnd
, WPARAM wParam
)
884 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
885 DATETIME_Refresh (hwnd
, hdc
);
887 EndPaint (hwnd
, &ps
);
893 DATETIME_ParentNotify (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
895 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
896 LPNMHDR lpnmh
= (LPNMHDR
) lParam
;
898 TRACE ("%x,%lx\n",wParam
, lParam
);
899 TRACE ("Got notification %x from %x\n", lpnmh
->code
, lpnmh
->hwndFrom
);
900 TRACE ("info: %x %x %x\n",hwnd
,infoPtr
->hMonthCal
,infoPtr
->hUpdown
);
906 DATETIME_Notify (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
909 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
910 LPNMHDR lpnmh
= (LPNMHDR
) lParam
;
912 TRACE ("%x,%lx\n",wParam
, lParam
);
913 TRACE ("Got notification %x from %x\n", lpnmh
->code
, lpnmh
->hwndFrom
);
914 TRACE ("info: %x %x %x\n",hwnd
,infoPtr
->hMonthCal
,infoPtr
->hUpdown
);
920 DATETIME_KeyDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
922 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
925 TRACE("%x %lx %x\n",wParam
, lParam
, infoPtr
->select
);
927 FieldNum
= infoPtr
->select
& DTHT_DATEFIELD
;
929 if (!(infoPtr
->haveFocus
)) return 0;
930 if ((FieldNum
==0) && (infoPtr
->select
)) return 0;
932 if (infoPtr
->select
& FORMATCALLMASK
) {
933 FIXME ("Callbacks not implemented yet\n");
939 DATETIME_IncreaseField (infoPtr
,FieldNum
);
940 DATETIME_SendDateTimeChangeNotify (hwnd
);
944 DATETIME_DecreaseField (infoPtr
,FieldNum
);
945 DATETIME_SendDateTimeChangeNotify (hwnd
);
948 DATETIME_ResetFieldDown (infoPtr
,FieldNum
);
949 DATETIME_SendDateTimeChangeNotify (hwnd
);
952 DATETIME_ResetFieldUp(infoPtr
,FieldNum
);
953 DATETIME_SendDateTimeChangeNotify (hwnd
);
957 if (infoPtr
->select
==0) {
958 infoPtr
->select
= infoPtr
->nrFields
- 1;
963 while ((infoPtr
->fieldspec
[infoPtr
->select
] & DT_STRING
) && (wrap
<2));
968 if (infoPtr
->select
==infoPtr
->nrFields
) {
973 while ((infoPtr
->fieldspec
[infoPtr
->select
] & DT_STRING
) && (wrap
<2));
977 InvalidateRect(hwnd
, NULL
, FALSE
);
984 DATETIME_KillFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
986 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
990 if (infoPtr
->haveFocus
) {
991 DATETIME_SendSimpleNotify (hwnd
, NM_KILLFOCUS
);
992 infoPtr
->haveFocus
= 0;
995 InvalidateRect (hwnd
, NULL
, TRUE
);
1002 DATETIME_SetFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1004 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
1008 if (infoPtr
->haveFocus
==0) {
1009 DATETIME_SendSimpleNotify (hwnd
, NM_SETFOCUS
);
1010 infoPtr
->haveFocus
= DTHT_GOTFOCUS
;
1013 InvalidateRect(hwnd
, NULL
, FALSE
);
1020 DATETIME_SendDateTimeChangeNotify (HWND hwnd
)
1023 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
1024 NMDATETIMECHANGE dtdtc
;
1027 dtdtc
.nmhdr
.hwndFrom
= hwnd
;
1028 dtdtc
.nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
1029 dtdtc
.nmhdr
.code
= DTN_DATETIMECHANGE
;
1031 if ((GetWindowLongA (hwnd
, GWL_STYLE
) & DTS_SHOWNONE
))
1032 dtdtc
.dwFlags
= GDT_NONE
;
1034 dtdtc
.dwFlags
= GDT_VALID
;
1036 MONTHCAL_CopyTime (&infoPtr
->date
, &dtdtc
.st
);
1037 return (BOOL
) SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1038 (WPARAM
)dtdtc
.nmhdr
.idFrom
, (LPARAM
)&dtdtc
);
1043 DATETIME_SendSimpleNotify (HWND hwnd
, UINT code
)
1048 nmhdr
.hwndFrom
= hwnd
;
1049 nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
1052 return (BOOL
) SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1053 (WPARAM
)nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
1057 DATETIME_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1059 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr(hwnd
);
1060 DWORD dwStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1063 infoPtr
->rcClient
.bottom
= HIWORD(lParam
);
1064 infoPtr
->rcClient
.right
= LOWORD(lParam
);
1066 TRACE("Height=%d, Width=%d\n", infoPtr
->rcClient
.bottom
, infoPtr
->rcClient
.right
);
1068 /* use DrawEdge to adjust the size of rcEdge to get rcDraw */
1069 memcpy((&infoPtr
->rcDraw
), (&infoPtr
->rcClient
), sizeof(infoPtr
->rcDraw
));
1071 DrawEdge((HDC
)NULL
, &(infoPtr
->rcDraw
), EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
1073 /* set the size of the button that drops the calender down */
1074 /* FIXME: account for style that allows button on left side */
1075 infoPtr
->calbutton
.top
= infoPtr
->rcDraw
.top
;
1076 infoPtr
->calbutton
.bottom
= infoPtr
->rcDraw
.bottom
;
1077 infoPtr
->calbutton
.left
= infoPtr
->rcDraw
.right
-15;
1078 infoPtr
->calbutton
.right
= infoPtr
->rcDraw
.right
;
1080 /* set enable/disable button size for show none style being enabled */
1081 /* FIXME: these dimensions are completely incorrect */
1082 infoPtr
->checkbox
.top
= infoPtr
->rcDraw
.top
;
1083 infoPtr
->checkbox
.bottom
= infoPtr
->rcDraw
.bottom
;
1084 infoPtr
->checkbox
.left
= infoPtr
->rcDraw
.left
;
1085 infoPtr
->checkbox
.right
= infoPtr
->rcDraw
.left
+ 10;
1087 /* update the position of the monthcal control */
1088 if(dwStyle
& DTS_RIGHTALIGN
)
1089 infoPtr
->monthcal_pos
.x
= infoPtr
->rcClient
.right
- ((infoPtr
->calbutton
.right
-
1090 infoPtr
->calbutton
.left
) + 145);
1092 infoPtr
->monthcal_pos
.x
= 8;
1094 infoPtr
->monthcal_pos
.y
= infoPtr
->rcClient
.bottom
;
1095 ClientToScreen (hwnd
, &(infoPtr
->monthcal_pos
));
1096 SetWindowPos(infoPtr
->hMonthCal
, 0, infoPtr
->monthcal_pos
.x
,
1097 infoPtr
->monthcal_pos
.y
,
1100 InvalidateRect(hwnd
, NULL
, FALSE
);
1107 DATETIME_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1109 DATETIME_INFO
*infoPtr
;
1110 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
1112 /* allocate memory for info structure */
1113 TRACE("%04x %08lx\n",wParam
,lParam
);
1114 infoPtr
= (DATETIME_INFO
*)COMCTL32_Alloc (sizeof(DATETIME_INFO
));
1115 if (infoPtr
== NULL
) {
1116 ERR("could not allocate info memory!\n");
1120 SetWindowLongA (hwnd
, 0, (DWORD
)infoPtr
);
1122 if (dwStyle
& DTS_SHOWNONE
) {
1123 infoPtr
->hwndCheckbut
=CreateWindowExA (0,"button", 0,
1124 WS_CHILD
| WS_VISIBLE
| BS_AUTOCHECKBOX
,
1127 0, GetWindowLongA (hwnd
, GWL_HINSTANCE
), 0);
1128 SendMessageA (infoPtr
->hwndCheckbut
, BM_SETCHECK
, 1, 0);
1131 if (dwStyle
& DTS_UPDOWN
) {
1132 infoPtr
->hUpdown
=CreateUpDownControl (
1133 WS_CHILD
| WS_BORDER
| WS_VISIBLE
,
1136 UD_MAXVAL
, UD_MINVAL
, 0);
1139 infoPtr
->fieldspec
= (int *) COMCTL32_Alloc (32*sizeof(int));
1140 infoPtr
->fieldRect
= (RECT
*) COMCTL32_Alloc (32*sizeof(RECT
));
1141 infoPtr
->buflen
= (int *) COMCTL32_Alloc (32*sizeof(int));
1142 infoPtr
->nrFieldsAllocated
= 32;
1144 DATETIME_SetFormat (hwnd
, 0, 0);
1146 /* create the monthcal control */
1147 infoPtr
->hMonthCal
= CreateWindowExA (0,"SysMonthCal32", 0,
1148 WS_BORDER
| WS_POPUP
| WS_CLIPSIBLINGS
,
1153 /* initialize info structure */
1154 GetSystemTime (&infoPtr
->date
);
1155 infoPtr
->dateValid
= TRUE
;
1156 infoPtr
->hFont
= GetStockObject(DEFAULT_GUI_FONT
);
1162 DATETIME_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1164 DATETIME_INFO
*infoPtr
= DATETIME_GetInfoPtr (hwnd
);
1167 COMCTL32_Free (infoPtr
);
1172 static LRESULT WINAPI
1173 DATETIME_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1178 case DTM_GETSYSTEMTIME
:
1179 DATETIME_GetSystemTime (hwnd
, wParam
, lParam
);
1181 case DTM_SETSYSTEMTIME
:
1182 DATETIME_SetSystemTime (hwnd
, wParam
, lParam
);
1185 FIXME("Unimplemented msg DTM_GETRANGE\n");
1189 FIXME("Unimplemented msg DTM_SETRANGE\n");
1192 case DTM_SETFORMATA
:
1193 return DATETIME_SetFormat (hwnd
, wParam
, lParam
);
1195 case DTM_SETFORMATW
:
1196 return DATETIME_SetFormatW (hwnd
, wParam
, lParam
);
1198 case DTM_SETMCCOLOR
:
1199 return DATETIME_SetMonthCalColor (hwnd
, wParam
, lParam
);
1201 case DTM_GETMCCOLOR
:
1202 return DATETIME_GetMonthCalColor (hwnd
, wParam
);
1204 case DTM_GETMONTHCAL
:
1205 return DATETIME_GetMonthCal (hwnd
);
1208 return DATETIME_SetMonthCalFont (hwnd
, wParam
, lParam
);
1211 return DATETIME_GetMonthCalFont (hwnd
);
1213 case WM_PARENTNOTIFY
:
1214 return DATETIME_ParentNotify (hwnd
, wParam
, lParam
);
1217 return DATETIME_Notify (hwnd
, wParam
, lParam
);
1220 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1223 return DATETIME_Paint (hwnd
, wParam
);
1226 return DATETIME_KeyDown (hwnd
, wParam
, lParam
);
1229 return DATETIME_KillFocus (hwnd
, wParam
, lParam
);
1232 return DATETIME_SetFocus (hwnd
, wParam
, lParam
);
1235 return DATETIME_Size (hwnd
, wParam
, lParam
);
1237 case WM_LBUTTONDOWN
:
1238 return DATETIME_LButtonDown (hwnd
, wParam
, lParam
);
1241 return DATETIME_LButtonUp (hwnd
, wParam
, lParam
);
1244 return DATETIME_Create (hwnd
, wParam
, lParam
);
1247 return DATETIME_Destroy (hwnd
, wParam
, lParam
);
1250 if (uMsg
>= WM_USER
)
1251 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
1252 uMsg
, wParam
, lParam
);
1253 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
1260 DATETIME_Register (void)
1265 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
1266 wndClass
.style
= CS_GLOBALCLASS
;
1267 wndClass
.lpfnWndProc
= (WNDPROC
)DATETIME_WindowProc
;
1268 wndClass
.cbClsExtra
= 0;
1269 wndClass
.cbWndExtra
= sizeof(DATETIME_INFO
*);
1270 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
1271 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1272 wndClass
.lpszClassName
= DATETIMEPICK_CLASSA
;
1274 RegisterClassA (&wndClass
);
1279 DATETIME_Unregister (void)
1282 UnregisterClassA (DATETIMEPICK_CLASSA
, (HINSTANCE
)NULL
);