2 /* Month calendar control
6 * Copyright 1998, 1999 Eric Kohl (ekohl@abo.rhein-zeitung.de)
7 * Copyright 1999 Alex Priem (alexp@sci.kun.nl)
13 * FIXME: refresh should ask for rect of required length. (?)
14 * FIXME: we refresh to often; especially in LButtonDown/MouseMove.
15 * FIXME: handle resources better (doesn't work now); also take care
16 of internationalization.
17 * FIXME: keyboard handling.
28 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(monthcal
)
32 /* take #days/month from ole/parsedt.c;
33 * we want full month-names, and abbreviated weekdays, so these are
37 char *monthtxt
[] = {"January", "February", "March", "April", "May",
38 "June", "July", "August", "September", "October",
39 "November", "December"};
41 char *daytxt
[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
42 int DayOfWeekTable
[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
46 #define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)GetWindowLongA (hwnd, 0))
49 * MONTHCAL_ValidateTime: is time a valid date/time combo?
53 /* CHECKME: all these validations OK? */
55 static int MONTHCAL_ValidateTime (SYSTEMTIME time
)
58 if (time
.wMonth
> 12) return FALSE
;
59 if (time
.wDayOfWeek
> 6) return FALSE
;
60 if (time
.wDay
> mdays
[time
.wMonth
]) return FALSE
;
61 if (time
.wMonth
> 23) return FALSE
;
62 if (time
.wMinute
> 60) return FALSE
;
63 if (time
.wSecond
> 60) return FALSE
;
64 if (time
.wMilliseconds
> 100) return FALSE
;
68 void MONTHCAL_CopyTime (const SYSTEMTIME
*from
, SYSTEMTIME
*to
)
71 to
->wYear
=from
->wYear
;
72 to
->wMonth
=from
->wMonth
;
73 to
->wDayOfWeek
=from
->wDayOfWeek
;
75 to
->wHour
=from
->wHour
;
76 to
->wMinute
=from
->wMinute
;
77 to
->wSecond
=from
->wSecond
;
78 to
->wMilliseconds
=from
->wMilliseconds
;
82 /* Note:Depending on DST, this may be offset by a day.
83 Need to find out if we're on a DST place & adjust the clock accordingly.
84 Above function assumes we have a valid data.
85 Valid for year>1752; d <= 1 <= 31, 1 <= m <= 12.
90 int MONTHCAL_CalculateDayOfWeek (DWORD day
, DWORD month
, DWORD year
)
94 return (year
+ year
/4 - year
/100 + year
/400 +
95 DayOfWeekTable
[month
-1] + day
- 1 ) % 7;
99 static int MONTHCAL_CalcDayFromPos (MONTHCAL_INFO
*infoPtr
, int x
, int y
)
102 int daypos
,weekpos
,retval
,firstDay
;
104 daypos
=(x
- infoPtr
->prevmonth
.left
) / infoPtr
->textWidth
;
105 weekpos
=(y
- infoPtr
->days
.bottom
- infoPtr
->rcClient
.top
) /
106 (infoPtr
->textHeight
*1.25);
107 firstDay
=MONTHCAL_CalculateDayOfWeek (1,infoPtr
->currentMonth
,infoPtr
->currentYear
);
108 retval
=daypos
+ 7*weekpos
- firstDay
;
109 TRACE ("%d %d %d\n",daypos
,weekpos
,retval
);
114 static void MONTHCAL_CalcDayXY (MONTHCAL_INFO
*infoPtr
, int day
, int month
,
118 int firstDay
,prevMonth
;
120 firstDay
=MONTHCAL_CalculateDayOfWeek (1,infoPtr
->currentMonth
,infoPtr
->currentYear
);
122 if (month
==infoPtr
->currentMonth
) {
123 *x
=(day
+firstDay
) & 7;
124 *y
=(day
+firstDay
-*x
) / 7;
127 if (month
< infoPtr
->currentMonth
) {
129 if (prevMonth
==0) prevMonth
=11;
130 *x
=(mdays
[prevMonth
]-firstDay
) & 7;
135 *x
=(day
+firstDay
+mdays
[month
]) & 7;
139 static void MONTHCAL_CalcDayRect (MONTHCAL_INFO
*infoPtr
, RECT
*r
, int x
, int y
)
141 r
->left
= infoPtr
->prevmonth
.left
+ x
* infoPtr
->textWidth
;
142 r
->right
= r
->left
+ infoPtr
->textWidth
;
143 r
->top
= infoPtr
->rcClient
.top
+ y
* 1.25 * infoPtr
->textHeight
144 + infoPtr
->days
.bottom
;
145 r
->bottom
= r
->top
+ infoPtr
->textHeight
;
149 static inline void MONTHCAL_CalcPosFromDay (MONTHCAL_INFO
*infoPtr
,
150 int day
, int month
, RECT
*r
)
155 MONTHCAL_CalcDayXY (infoPtr
, day
, month
, &x
, &y
);
156 MONTHCAL_CalcDayRect (infoPtr
, r
, x
, y
);
162 static void MONTHCAL_CircleDay (HDC hdc
, MONTHCAL_INFO
*infoPtr
, int i
, int j
)
165 HPEN hRedPen
= CreatePen(PS_SOLID
, 2, RGB (255,0,0) );
166 HPEN hOldPen2
= SelectObject( hdc
, hRedPen
);
170 /* use prevmonth to calculate position because it contains the extra width
171 * from MCS_WEEKNUMBERS
174 x
=infoPtr
->prevmonth
.left
+ (i
+0.5)*infoPtr
->textWidth
;
175 y
=infoPtr
->rcClient
.top
+ 1.25*(j
+0.5)*infoPtr
->textHeight
+ infoPtr
->days
.bottom
;
177 points
[0].y
= y
-0.25*infoPtr
->textHeight
;
178 points
[1].x
= x
-1.0*infoPtr
->textWidth
;
181 points
[2].y
= y
+0.6*infoPtr
->textHeight
;
182 points
[3].x
= x
+0.5*infoPtr
->textWidth
;
184 points
[4].x
= x
+0.3*infoPtr
->textWidth
;
185 points
[4].y
= y
-0.5*infoPtr
->textHeight
;
186 points
[5].x
= x
-0.25*infoPtr
->textWidth
;
187 points
[5].y
= y
-0.5*infoPtr
->textHeight
;
188 points
[6].x
= x
-0.5*infoPtr
->textWidth
;
189 points
[6].y
= y
-0.45*infoPtr
->textHeight
;
191 PolyBezier (hdc
,points
,4);
192 PolyBezier (hdc
,points
+3,4);
193 DeleteObject (hRedPen
);
194 SelectObject (hdc
, hOldPen2
);
201 static void MONTHCAL_DrawDay (HDC hdc
, MONTHCAL_INFO
*infoPtr
,
202 int day
, int month
, int x
, int y
, int bold
)
207 static int haveBoldFont
,haveSelectedDay
=FALSE
;
209 COLORREF oldCol
,oldBk
;
211 sprintf (buf
,"%d",day
);
215 /* No need to check styles: when selection is not valid, it is set to zero.
216 * 1<day<31, so evertyhing's OK.
219 MONTHCAL_CalcDayRect (infoPtr
, &r
, x
, y
);
221 if ((day
>=infoPtr
->minSel
.wDay
) && (day
<=infoPtr
->maxSel
.wDay
)
222 && (month
==infoPtr
->currentMonth
)) {
226 TRACE ("%d %d %d\n",day
,infoPtr
->minSel
.wDay
,infoPtr
->maxSel
.wDay
);
227 TRACE ("%d %d %d %d\n", r
.left
, r
.top
, r
.right
, r
.bottom
);
228 oldCol
=SetTextColor (hdc
, infoPtr
->monthbk
);
229 oldBk
=SetBkColor (hdc
,infoPtr
->trailingtxt
);
230 hbr
= GetSysColorBrush (COLOR_GRAYTEXT
);
231 hrgn
=CreateEllipticRgn (r
.left
,r
.top
, r
.right
,r
.bottom
);
232 FillRgn (hdc
,hrgn
,hbr
);
234 r2
.left
= r
.left
-0.25*infoPtr
->textWidth
;
236 r2
.right
= r
.left
+0.5*infoPtr
->textWidth
;
237 r2
.bottom
= r
.bottom
;
238 if (haveSelectedDay
) FillRect (hdc
,&r2
,hbr
);
239 haveSelectedDay
=TRUE
;
241 haveSelectedDay
=FALSE
;
246 /* need to add some code for multiple selections */
248 if ((bold
) && (!haveBoldFont
)) {
249 SelectObject (hdc
, infoPtr
->hBoldFont
);
252 if ((!bold
) && (haveBoldFont
)) {
253 SelectObject (hdc
, infoPtr
->hFont
);
259 DrawTextA ( hdc
, buf
, lstrlenA(buf
), &r
,
260 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
);
261 if (haveSelectedDay
) {
262 SetTextColor(hdc
, oldCol
);
263 SetBkColor (hdc
, oldBk
);
266 if ((day
==infoPtr
->curSelDay
) && (month
==infoPtr
->currentMonth
)) {
267 HPEN hNewPen
, hOldPen
;
269 hNewPen
= CreatePen(PS_DOT
, 0, GetSysColor(COLOR_WINDOWTEXT
) );
270 hbr
= GetSysColorBrush (COLOR_WINDOWTEXT
);
271 hOldPen
= SelectObject( hdc
, hNewPen
);
276 FrameRect (hdc
, &r
, hbr
);
277 SelectObject( hdc
, hOldPen
);
282 /* CHECKME: For `todays date', do we need to check the locale?*/
283 /* CHECKME: For `todays date', how do is Y2K handled?*/
284 /* FIXME: todays date circle */
286 static void MONTHCAL_Refresh (HWND hwnd
, HDC hdc
)
289 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
290 RECT
*rcClient
=&infoPtr
->rcClient
;
291 RECT
*title
=&infoPtr
->title
;
292 RECT
*prev
=&infoPtr
->titlebtnprev
;
293 RECT
*next
=&infoPtr
->titlebtnnext
;
294 RECT
*titlemonth
=&infoPtr
->titlemonth
;
295 RECT
*titleyear
=&infoPtr
->titleyear
;
296 RECT
*prevmonth
=&infoPtr
->prevmonth
;
297 RECT
*nextmonth
=&infoPtr
->nextmonth
;
298 RECT
*days
=&infoPtr
->days
;
299 RECT
*weeknums
=&infoPtr
->weeknums
;
300 RECT
*rtoday
=&infoPtr
->today
;
301 int i
,j
,m
,mask
,day
,firstDay
, weeknum
,prevMonth
;
302 int textHeight
,textWidth
;
307 /* LOGFONTA logFont; */
308 char buf
[20],*thisMonthtxt
;
309 COLORREF oldTextColor
,oldBkColor
;
310 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
314 oldTextColor
= SetTextColor(hdc
, GetSysColor( COLOR_WINDOWTEXT
));
316 currentFont
= SelectObject (hdc
, infoPtr
->hFont
);
318 /* FIXME: need a way to determine current font, without setting it */
320 if (infoPtr->hFont!=currentFont) {
321 SelectObject (hdc, currentFont);
322 infoPtr->hFont=currentFont;
323 GetObjectA (currentFont, sizeof (LOGFONTA), &logFont);
324 logFont.lfWeight=FW_BOLD;
325 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
329 GetTextMetricsA (hdc
, &tm
);
330 infoPtr
->textHeight
=textHeight
=tm
.tmHeight
+ tm
.tmExternalLeading
;
331 GetTextExtentPoint32A (hdc
, "Sun",3, &size
);
332 infoPtr
->textWidth
=textWidth
=size
.cx
+2;
334 GetClientRect (hwnd
, rcClient
);
335 hbr
= CreateSolidBrush (RGB(255,255,255));
336 DrawEdge (hdc
, rcClient
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
337 FillRect (hdc
, rcClient
, hbr
);
340 /* calculate whole client area & title area */
342 infoPtr
->rcClient
.right
=7*infoPtr
->textWidth
;
343 if (dwStyle
& MCS_WEEKNUMBERS
)
344 infoPtr
->rcClient
.right
+=infoPtr
->textWidth
;
346 title
->top
= rcClient
->top
+ 1;
347 title
->bottom
= title
->top
+ 2*textHeight
+ 4;
348 title
->left
= rcClient
->left
+ 1;
349 title
->right
= rcClient
->right
- 1;
350 infoPtr
->rcClient
.bottom
=title
->bottom
+ 6*textHeight
;
355 hbr
= CreateSolidBrush (infoPtr
->titlebk
);
356 FillRect (hdc
, title
, hbr
);
358 prev
->top
= next
->top
= title
->top
+ 6;
359 prev
->bottom
= next
->bottom
= title
->top
+ 2*textHeight
- 3;
360 prev
->right
= title
->left
+ 28;
361 prev
->left
= title
->left
+ 4;
362 next
->left
= title
->right
- 28;
363 next
->right
= title
->right
- 4;
364 titlemonth
->bottom
= titleyear
->bottom
= prev
->top
+ 2*textHeight
- 3;
365 titlemonth
->top
= titleyear
->top
= title
->top
+ 6;
366 titlemonth
->left
= title
->left
;
367 titlemonth
->right
= title
->right
;
370 if (!(infoPtr
->status
& MC_PREVPRESSED
))
371 DrawFrameControl(hdc
, prev
, DFC_SCROLL
,
372 DFCS_SCROLLLEFT
| (dwStyle
& WS_DISABLED
? DFCS_INACTIVE
: 0) );
374 if (!(infoPtr
->status
& MC_NEXTPRESSED
))
375 DrawFrameControl(hdc
, next
, DFC_SCROLL
,
376 DFCS_SCROLLRIGHT
| (dwStyle
& WS_DISABLED
? DFCS_INACTIVE
: 0) );
378 oldBkColor
=SetBkColor (hdc
,infoPtr
->titlebk
);
379 SetTextColor(hdc
, infoPtr
->titletxt
);
380 SelectObject (hdc
, infoPtr
->hBoldFont
);
382 thisMonthtxt
=monthtxt
[infoPtr
->currentMonth
- 1];
383 sprintf (buf
,"%s %ld",thisMonthtxt
,infoPtr
->currentYear
);
384 DrawTextA ( hdc
, buf
, strlen(buf
), titlemonth
,
385 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
);
386 SelectObject (hdc
, infoPtr
->hFont
);
388 /* titlemonth left/right contained rect for whole titletxt ('June 1999')
389 * MCM_HitTestInfo wants month & year rects, so prepare these now.
390 * (no, we can't draw them separately; the whole text is centered)
393 GetTextExtentPoint32A (hdc
, buf
,lstrlenA (buf
), &size
);
394 titlemonth
->left
= title
->right
/2 - size
.cx
/2;
395 titleyear
->right
= title
->right
/2 + size
.cx
/2;
396 GetTextExtentPoint32A (hdc
, thisMonthtxt
,lstrlenA (thisMonthtxt
), &size
);
397 titlemonth
->right
= titlemonth
->left
+size
.cx
;
398 titleyear
->right
= titlemonth
->right
;
400 /* draw line under day abbreviatons */
402 if (dwStyle
& MCS_WEEKNUMBERS
)
403 MoveToEx (hdc
, rcClient
->left
+textWidth
+3,
404 title
->bottom
+ textHeight
+ 2, NULL
);
406 MoveToEx (hdc
, rcClient
->left
+3, title
->bottom
+ textHeight
+ 2, NULL
);
407 LineTo (hdc
, rcClient
->right
-3, title
->bottom
+ textHeight
+ 2);
409 /* draw day abbreviations */
411 SetBkColor (hdc
, infoPtr
->monthbk
);
412 SetTextColor(hdc
, infoPtr
->trailingtxt
);
414 days
->left
= rcClient
->left
;
415 if (dwStyle
& MCS_WEEKNUMBERS
) days
->left
+=textWidth
;
416 days
->right
= days
->left
+ textWidth
;
417 days
->top
= title
->bottom
+ 2;
418 days
->bottom
= title
->bottom
+ textHeight
+ 2;
421 for (j
=0; j
<7; j
++) {
422 DrawTextA ( hdc
, daytxt
[i
], strlen(daytxt
[i
]), days
,
423 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
);
426 days
->left
+=textWidth
;
427 days
->right
+=textWidth
;
430 days
->left
= rcClient
->left
+ j
;
431 if (dwStyle
& MCS_WEEKNUMBERS
) days
->left
+=textWidth
;
432 days
->right
= rcClient
->left
+ (j
+1)*textWidth
-2;
434 /* draw day numbers; first, the previous month */
437 if (dwStyle
& MCS_WEEKNUMBERS
) prevmonth
->left
=textWidth
;
439 firstDay
=MONTHCAL_CalculateDayOfWeek (1,infoPtr
->currentMonth
,infoPtr
->currentYear
);
440 prevMonth
=infoPtr
->currentMonth
-1;
441 if (prevMonth
==0) prevMonth
=11;
442 day
=mdays
[prevMonth
]-firstDay
;
447 while (day
<=mdays
[prevMonth
]) {
448 MONTHCAL_DrawDay (hdc
, infoPtr
, day
, prevMonth
, i
, 0,
449 infoPtr
->monthdayState
[m
] & mask
);
455 prevmonth
->right
= prevmonth
->left
+i
*textWidth
;
456 prevmonth
->top
= days
->bottom
;
457 prevmonth
->bottom
= prevmonth
->top
+ textHeight
;
459 /* draw `current' month */
462 infoPtr
->firstDayplace
=i
;
463 SetTextColor(hdc
, infoPtr
->txt
);
467 MONTHCAL_DrawDay (hdc
, infoPtr
, day
, infoPtr
->currentMonth
, i
, 0,
468 infoPtr
->monthdayState
[m
] & mask
);
469 if ((infoPtr
->currentMonth
==infoPtr
->todaysDate
.wMonth
) &&
470 (day
==infoPtr
->todaysDate
.wDay
))
471 MONTHCAL_CircleDay (hdc
, infoPtr
, i
,j
);
479 while (day
<=mdays
[infoPtr
->currentMonth
]) {
480 MONTHCAL_DrawDay (hdc
, infoPtr
, day
, infoPtr
->currentMonth
, i
, j
,
481 infoPtr
->monthdayState
[m
] & mask
);
482 if ((infoPtr
->currentMonth
==infoPtr
->todaysDate
.wMonth
) &&
483 (day
==infoPtr
->todaysDate
.wDay
))
484 MONTHCAL_CircleDay (hdc
, infoPtr
, i
,j
);
494 /* draw `next' month */
496 /* note: the nextmonth rect only hints for the `half-week' that needs to be
497 * drawn to complete the current week. An eventual next week that needs to
498 * be drawn to complete the month calendar is not taken into account in
499 * this rect -- HitTest knows about this.*/
503 nextmonth
->left
= prevmonth
->left
+i
*textWidth
;
504 nextmonth
->right
= rcClient
->right
;
505 nextmonth
->top
= days
->bottom
+(j
+1)*textHeight
;
506 nextmonth
->bottom
= nextmonth
->top
+ textHeight
;
511 SetTextColor(hdc
, infoPtr
->trailingtxt
);
512 while ((i
<7) && (j
<6)) {
513 MONTHCAL_DrawDay (hdc
, infoPtr
, day
, infoPtr
->currentMonth
+1, i
, j
,
514 infoPtr
->monthdayState
[m
] & mask
);
523 SetTextColor(hdc
, infoPtr
->txt
);
527 /* draw `today' date if style allows it, and draw a circle before today's
528 * date if necessairy */
530 if (!( dwStyle
& MCS_NOTODAY
)) {
532 if (!( dwStyle
& MCS_NOTODAYCIRCLE
)) {
533 MONTHCAL_CircleDay (hdc
, infoPtr
, 0, 6);
537 MONTHCAL_CalcDayRect (infoPtr
, rtoday
, offset
==textWidth
, 6);
538 sprintf (buf
,"Today: %d/%d/%d",infoPtr
->todaysDate
.wMonth
,
539 infoPtr
->todaysDate
.wDay
, infoPtr
->todaysDate
.wYear
-1900);
540 rtoday
->right
= rcClient
->right
;
541 SelectObject (hdc
, infoPtr
->hBoldFont
);
542 DrawTextA ( hdc
, buf
, lstrlenA(buf
), rtoday
,
543 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
);
544 SelectObject (hdc
, infoPtr
->hFont
);
547 if (dwStyle
& MCS_WEEKNUMBERS
) {
548 /* display weeknumbers*/
551 weeknums
->right
= textWidth
;
552 weeknums
->top
= days
->bottom
+ 2;
553 weeknums
->bottom
= days
->bottom
+ 2 + textHeight
;
556 for (i
=0; i
<infoPtr
->currentMonth
-1; i
++)
560 for (i
=0; i
<6; i
++) {
561 sprintf (buf
,"%d",weeknum
+i
);
562 DrawTextA ( hdc
, buf
, lstrlenA(buf
), weeknums
,
563 DT_CENTER
| DT_BOTTOM
| DT_SINGLELINE
);
564 weeknums
->top
+=textHeight
*1.25;
565 weeknums
->bottom
+=textHeight
*1.25;
568 MoveToEx (hdc
, weeknums
->right
, days
->bottom
+5 , NULL
);
569 LineTo (hdc
, weeknums
->right
, weeknums
->bottom
-1.25*textHeight
-5);
573 /* currentFont was font at entering Refresh */
575 SetBkColor (hdc
, oldBkColor
);
576 SelectObject (hdc
, currentFont
);
577 SetTextColor (hdc
, oldTextColor
);
582 MONTHCAL_GetMinReqRect (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
585 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
586 LPRECT lpRect
=(LPRECT
) lParam
;
587 TRACE ("%x %lx\n",wParam
,lParam
);
589 /* validate parameters */
591 if ( (infoPtr
==NULL
) || (lpRect
== NULL
) ) return FALSE
;
593 lpRect
->left
=infoPtr
->rcClient
.left
;
594 lpRect
->right
=infoPtr
->rcClient
.right
;
595 lpRect
->top
=infoPtr
->rcClient
.top
;
596 lpRect
->bottom
=infoPtr
->rcClient
.bottom
;
601 MONTHCAL_GetColor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
604 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
606 TRACE ("%x %lx\n",wParam
,lParam
);
608 switch ((int)wParam
) {
609 case MCSC_BACKGROUND
:
614 return infoPtr
->titlebk
;
616 return infoPtr
->titletxt
;
618 return infoPtr
->monthbk
;
619 case MCSC_TRAILINGTEXT
:
620 return infoPtr
->trailingtxt
;
627 MONTHCAL_SetColor (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
630 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
633 TRACE ("%x %lx\n",wParam
,lParam
);
635 switch ((int)wParam
) {
636 case MCSC_BACKGROUND
:
638 infoPtr
->bk
=(COLORREF
) lParam
;
642 infoPtr
->txt
=(COLORREF
) lParam
;
645 prev
=infoPtr
->titlebk
;
646 infoPtr
->titlebk
=(COLORREF
) lParam
;
649 prev
=infoPtr
->titletxt
;
650 infoPtr
->titletxt
=(COLORREF
) lParam
;
653 prev
=infoPtr
->monthbk
;
654 infoPtr
->monthbk
=(COLORREF
) lParam
;
656 case MCSC_TRAILINGTEXT
:
657 prev
=infoPtr
->trailingtxt
;
658 infoPtr
->trailingtxt
=(COLORREF
) lParam
;
666 MONTHCAL_GetMonthDelta (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
669 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
671 TRACE ("%x %lx\n",wParam
,lParam
);
673 if (infoPtr
->delta
) return infoPtr
->delta
;
674 else return infoPtr
->visible
;
678 MONTHCAL_SetMonthDelta (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
681 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
682 int prev
=infoPtr
->delta
;
684 TRACE ("%x %lx\n",wParam
,lParam
);
686 infoPtr
->delta
=(int) wParam
;
693 MONTHCAL_GetFirstDayOfWeek (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
695 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
697 return infoPtr
->firstDay
;
700 /* FIXME: we need more error checking here */
703 MONTHCAL_SetFirstDayOfWeek (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
706 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
707 int prev
=infoPtr
->firstDay
;
711 TRACE ("%x %lx\n",wParam
,lParam
);
713 if ((lParam
>=0) && (lParam
<7)) {
714 infoPtr
->firstDay
=(int) lParam
;
715 GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_IFIRSTDAYOFWEEK
,
717 TRACE ("%s %d\n",buf
,strlen(buf
));
718 if ((sscanf(buf
,"%d",&day
)==1) && (infoPtr
->firstDay
!=day
))
719 infoPtr
->firstDay
|=HIWORD(TRUE
);
727 /* FIXME: fill this in */
730 MONTHCAL_GetMonthRange (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
732 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
734 TRACE ("%x %lx\n",wParam
,lParam
);
736 return infoPtr
->monthRange
;
740 MONTHCAL_GetMaxTodayWidth (HWND hwnd
)
743 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
745 return (infoPtr
->today
.right
-infoPtr
->today
.left
);
748 /* FIXME: are validated times taken from current date/time or simply
750 * FIXME: check whether MCM_GETMONTHRANGE shows correct result after
751 * adjusting range with MCM_SETRANGE
755 MONTHCAL_SetRange (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
757 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
758 SYSTEMTIME lprgSysTimeArray
[1];
761 TRACE ("%x %lx\n",wParam
,lParam
);
763 if (wParam
& GDTR_MAX
) {
764 if (MONTHCAL_ValidateTime(lprgSysTimeArray
[1])){
765 MONTHCAL_CopyTime (&lprgSysTimeArray
[1],&infoPtr
->maxDate
);
766 infoPtr
->rangeValid
|=GDTR_MAX
;
768 GetSystemTime (&infoPtr
->todaysDate
);
769 MONTHCAL_CopyTime (&infoPtr
->todaysDate
,&infoPtr
->maxDate
);
772 if (wParam
& GDTR_MIN
) {
773 if (MONTHCAL_ValidateTime(lprgSysTimeArray
[0])) {
774 MONTHCAL_CopyTime (&lprgSysTimeArray
[0],&infoPtr
->maxDate
);
775 infoPtr
->rangeValid
|=GDTR_MIN
;
777 GetSystemTime (&infoPtr
->todaysDate
);
778 MONTHCAL_CopyTime (&infoPtr
->todaysDate
,&infoPtr
->maxDate
);
782 prev
=infoPtr
->monthRange
;
783 infoPtr
->monthRange
=infoPtr
->maxDate
.wMonth
-infoPtr
->minDate
.wMonth
;
784 if (infoPtr
->monthRange
!=prev
)
785 COMCTL32_ReAlloc (infoPtr
->monthdayState
,
786 infoPtr
->monthRange
*sizeof(MONTHDAYSTATE
));
792 /* CHECKME: At the moment, we copy ranges anyway,regardless of
793 * infoPtr->rangeValid; a invalid range is simply filled with zeros in
794 * SetRange. Is this the right behavior?
798 MONTHCAL_GetRange (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
800 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
801 SYSTEMTIME
*lprgSysTimeArray
=(SYSTEMTIME
*) lParam
;
803 /* validate parameters */
805 if ( (infoPtr
==NULL
) || (lprgSysTimeArray
==NULL
) ) return FALSE
;
807 MONTHCAL_CopyTime (&infoPtr
->maxDate
,&lprgSysTimeArray
[1]);
808 MONTHCAL_CopyTime (&infoPtr
->minDate
,&lprgSysTimeArray
[0]);
810 return infoPtr
->rangeValid
;
814 MONTHCAL_SetDayState (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
817 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
818 int i
,iMonths
=(int) wParam
;
819 MONTHDAYSTATE
*dayStates
=(LPMONTHDAYSTATE
) lParam
;
821 TRACE ("%x %lx\n",wParam
,lParam
);
822 if (iMonths
!=infoPtr
->monthRange
) return 0;
824 for (i
=0; i
<iMonths
; i
++)
825 infoPtr
->monthdayState
[i
]=dayStates
[i
];
830 MONTHCAL_GetCurSel (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
832 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
833 SYSTEMTIME
*lpSel
=(SYSTEMTIME
*) lParam
;
835 TRACE ("%x %lx\n",wParam
,lParam
);
836 if ( (infoPtr
==NULL
) || (lpSel
==NULL
) ) return FALSE
;
837 if ( GetWindowLongA( hwnd
, GWL_STYLE
) & MCS_MULTISELECT
) return FALSE
;
839 MONTHCAL_CopyTime (&infoPtr
->minSel
,lpSel
);
844 /* FIXME: if the specified date is not visible, make it visible */
848 MONTHCAL_SetCurSel (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
850 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
851 SYSTEMTIME
*lpSel
=(SYSTEMTIME
*) lParam
;
853 TRACE ("%x %lx\n",wParam
,lParam
);
854 if ( (infoPtr
==NULL
) || (lpSel
==NULL
) ) return FALSE
;
855 if ( GetWindowLongA( hwnd
, GWL_STYLE
) & MCS_MULTISELECT
) return FALSE
;
857 TRACE ("%d %d\n",lpSel
->wMonth
,lpSel
->wDay
);
859 MONTHCAL_CopyTime (lpSel
,&infoPtr
->minSel
);
860 MONTHCAL_CopyTime (lpSel
,&infoPtr
->maxSel
);
866 MONTHCAL_GetMaxSelCount (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
868 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
870 TRACE ("%x %lx\n",wParam
,lParam
);
871 return infoPtr
->maxSelCount
;
875 MONTHCAL_SetMaxSelCount (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
877 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
879 TRACE ("%x %lx\n",wParam
,lParam
);
880 if ( GetWindowLongA( hwnd
, GWL_STYLE
) & MCS_MULTISELECT
) {
881 infoPtr
->maxSelCount
=wParam
;
889 MONTHCAL_GetSelRange (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
891 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
892 SYSTEMTIME
*lprgSysTimeArray
=(SYSTEMTIME
*) lParam
;
894 TRACE ("%x %lx\n",wParam
,lParam
);
896 /* validate parameters */
898 if ( (infoPtr
==NULL
) || (lprgSysTimeArray
==NULL
) ) return FALSE
;
900 if ( GetWindowLongA( hwnd
, GWL_STYLE
) & MCS_MULTISELECT
) {
901 MONTHCAL_CopyTime (&infoPtr
->maxSel
,&lprgSysTimeArray
[1]);
902 MONTHCAL_CopyTime (&infoPtr
->minSel
,&lprgSysTimeArray
[0]);
903 TRACE ("[min,max]=[%d %d]\n",infoPtr
->minSel
.wDay
,infoPtr
->maxSel
.wDay
);
911 MONTHCAL_SetSelRange (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
913 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
914 SYSTEMTIME
*lprgSysTimeArray
=(SYSTEMTIME
*) lParam
;
916 TRACE ("%x %lx\n",wParam
,lParam
);
918 /* validate parameters */
920 if ( (infoPtr
==NULL
) || (lprgSysTimeArray
==NULL
) ) return FALSE
;
922 if ( GetWindowLongA( hwnd
, GWL_STYLE
) & MCS_MULTISELECT
) {
923 MONTHCAL_CopyTime (&lprgSysTimeArray
[1],&infoPtr
->maxSel
);
924 MONTHCAL_CopyTime (&lprgSysTimeArray
[0],&infoPtr
->minSel
);
925 TRACE ("[min,max]=[%d %d]\n",infoPtr
->minSel
.wDay
,infoPtr
->maxSel
.wDay
);
936 MONTHCAL_GetToday (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
938 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
939 SYSTEMTIME
*lpToday
=(SYSTEMTIME
*) lParam
;
941 TRACE ("%x %lx\n",wParam
,lParam
);
943 /* validate parameters */
945 if ( (infoPtr
==NULL
) || (lpToday
==NULL
) ) return FALSE
;
946 MONTHCAL_CopyTime (&infoPtr
->todaysDate
,lpToday
);
952 MONTHCAL_SetToday (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
954 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
955 SYSTEMTIME
*lpToday
=(SYSTEMTIME
*) lParam
;
957 TRACE ("%x %lx\n",wParam
,lParam
);
959 /* validate parameters */
961 if ( (infoPtr
==NULL
) || (lpToday
==NULL
) ) return FALSE
;
962 MONTHCAL_CopyTime (lpToday
, &infoPtr
->todaysDate
);
970 MONTHCAL_HitTest (HWND hwnd
, LPARAM lParam
)
972 MONTHCAL_INFO
*infoPtr
=MONTHCAL_GetInfoPtr(hwnd
);
973 PMCHITTESTINFO lpht
=(PMCHITTESTINFO
) lParam
;
982 /* are we in the header? */
984 if (PtInRect (&infoPtr
->title
, lpht
->pt
)) {
986 if (PtInRect (&infoPtr
->titlebtnprev
, lpht
->pt
)) {
987 retval
=MCHT_TITLEBTNPREV
;
990 if (PtInRect (&infoPtr
->titlebtnnext
, lpht
->pt
)) {
991 retval
=MCHT_TITLEBTNNEXT
;
994 if (PtInRect (&infoPtr
->titlemonth
, lpht
->pt
)) {
995 retval
=MCHT_TITLEMONTH
;
998 if (PtInRect (&infoPtr
->titleyear
, lpht
->pt
)) {
999 retval
=MCHT_TITLEYEAR
;
1006 if (PtInRect (&infoPtr
->days
, lpht
->pt
)) {
1007 retval
=MCHT_CALENDARDAY
; /* FIXME: find out which day we're on */
1010 if (PtInRect (&infoPtr
->weeknums
, lpht
->pt
)) {
1011 retval
=MCHT_CALENDARWEEKNUM
;/* FIXME: find out which day we're on */
1014 if (PtInRect (&infoPtr
->prevmonth
, lpht
->pt
)) {
1015 retval
=MCHT_CALENDARDATEPREV
;
1018 if (PtInRect (&infoPtr
->nextmonth
, lpht
->pt
) ||
1019 ((x
>infoPtr
->nextmonth
.left
) && (x
<infoPtr
->nextmonth
.right
) &&
1020 (y
>infoPtr
->nextmonth
.bottom
) && (y
<infoPtr
->today
.top
))) {
1021 retval
=MCHT_CALENDARDATENEXT
;
1026 if (PtInRect (&infoPtr
->today
, lpht
->pt
)) {
1027 retval
=MCHT_TODAYLINK
;
1031 /* MCHT_CALENDARDATE determination: since the next & previous month have
1032 * been handled already (MCHT_CALENDARDATEPREV/NEXT), we only have to check
1033 * whether we're in the calendar area. infoPtr->prevMonth.left handles the
1034 * MCS_WEEKNUMBERS style nicely.
1038 TRACE ("%d %d [%d %d %d %d] [%d %d %d %d]\n",x
,y
,
1039 infoPtr
->prevmonth
.left
, infoPtr
->prevmonth
.right
,
1040 infoPtr
->prevmonth
.top
, infoPtr
->prevmonth
.bottom
,
1041 infoPtr
->nextmonth
.left
, infoPtr
->nextmonth
.right
,
1042 infoPtr
->nextmonth
.top
, infoPtr
->nextmonth
.bottom
);
1044 if ((x
>infoPtr
->prevmonth
.left
) && (x
<infoPtr
->nextmonth
.right
) &&
1045 (y
>infoPtr
->prevmonth
.top
) && (y
<infoPtr
->nextmonth
.bottom
)) {
1046 lpht
->st
.wYear
=infoPtr
->currentYear
;
1047 lpht
->st
.wMonth
=infoPtr
->currentMonth
;
1049 lpht
->st
.wDay
=MONTHCAL_CalcDayFromPos (infoPtr
,x
,y
);
1051 TRACE ("day hit: %d\n",lpht
->st
.wDay
);
1052 retval
=MCHT_CALENDARDATE
;
1057 /* Hit nothing special? What's left must be background :-) */
1059 retval
=MCHT_CALENDARBK
;
1067 static void MONTHCAL_GoToNextMonth (HWND hwnd
, MONTHCAL_INFO
*infoPtr
)
1069 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
1073 infoPtr
->currentMonth
++;
1074 if (infoPtr
->currentMonth
>12) {
1075 infoPtr
->currentYear
++;
1076 infoPtr
->currentMonth
=1;
1079 if (dwStyle
& MCS_DAYSTATE
) {
1083 nmds
.nmhdr
.hwndFrom
= hwnd
;
1084 nmds
.nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
1085 nmds
.nmhdr
.code
= MCN_GETDAYSTATE
;
1086 nmds
.cDayState
= infoPtr
->monthRange
;
1087 nmds
.prgDayState
= COMCTL32_Alloc
1088 (infoPtr
->monthRange
*sizeof(MONTHDAYSTATE
));
1090 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1091 (WPARAM
)nmds
.nmhdr
.idFrom
, (LPARAM
)&nmds
);
1092 for (i
=0; i
<infoPtr
->monthRange
; i
++)
1093 infoPtr
->monthdayState
[i
]=nmds
.prgDayState
[i
];
1099 static void MONTHCAL_GoToPrevMonth (HWND hwnd
, MONTHCAL_INFO
*infoPtr
)
1101 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
1105 infoPtr
->currentMonth
--;
1106 if (infoPtr
->currentMonth
<1) {
1107 infoPtr
->currentYear
--;
1108 infoPtr
->currentMonth
=12;
1111 if (dwStyle
& MCS_DAYSTATE
) {
1115 nmds
.nmhdr
.hwndFrom
= hwnd
;
1116 nmds
.nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
1117 nmds
.nmhdr
.code
= MCN_GETDAYSTATE
;
1118 nmds
.cDayState
= infoPtr
->monthRange
;
1119 nmds
.prgDayState
= COMCTL32_Alloc
1120 (infoPtr
->monthRange
*sizeof(MONTHDAYSTATE
));
1122 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1123 (WPARAM
)nmds
.nmhdr
.idFrom
, (LPARAM
)&nmds
);
1124 for (i
=0; i
<infoPtr
->monthRange
; i
++)
1125 infoPtr
->monthdayState
[i
]=nmds
.prgDayState
[i
];
1131 MONTHCAL_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1134 MONTHCAL_INFO
*infoPtr
= MONTHCAL_GetInfoPtr (hwnd
);
1142 TRACE ("%x %lx\n",wParam
,lParam
);
1144 ht
.pt
.x
= (INT
)LOWORD(lParam
);
1145 ht
.pt
.y
= (INT
)HIWORD(lParam
);
1146 hit
=MONTHCAL_HitTest (hwnd
, (LPARAM
) &ht
);
1150 if (hit
& MCHT_NEXT
){
1151 MONTHCAL_GoToNextMonth (hwnd
, infoPtr
);
1152 infoPtr
->status
=MC_NEXTPRESSED
;
1153 SetTimer (hwnd
, MC_NEXTMONTHTIMER
, MC_NEXTMONTHDELAY
,0);
1155 if (hit
& MCHT_PREV
) {
1156 MONTHCAL_GoToPrevMonth (hwnd
, infoPtr
);
1157 infoPtr
->status
=MC_PREVPRESSED
;
1158 SetTimer (hwnd
, MC_PREVMONTHTIMER
, MC_NEXTMONTHDELAY
,0);
1161 if (hit
== MCHT_TITLEMONTH
) {
1163 HRSRC hrsrc = FindResourceA( COMCTL32_hModule, MAKEINTRESOURCEA(IDD_MCMONTHMENU), RT_MENUA );
1165 TRACE ("returning zero\n");
1168 TRACE ("resource is:%x\n",hrsrc);
1169 hMenu=LoadMenuIndirectA( (LPCVOID)LoadResource( COMCTL32_hModule, hrsrc ));
1171 TRACE ("menu is:%x\n",hMenu);
1174 hMenu
=CreateMenu ();
1175 AppendMenuA (hMenu
,MF_STRING
,IDM_JAN
,"January");
1176 AppendMenuA (hMenu
,MF_STRING
,IDM_FEB
,"February");
1177 AppendMenuA (hMenu
,MF_STRING
,IDM_MAR
,"March");
1179 retval
=CreateWindowA (POPUPMENU_CLASS_ATOM
, NULL
,
1180 WS_CHILD
| WS_VISIBLE
,
1182 hwnd
, hMenu
, GetWindowLongA (hwnd
, GWL_HINSTANCE
), NULL
);
1183 TRACE ("hwnd returned:%x\n",retval
);
1186 if (hit
== MCHT_TITLEYEAR
) {
1187 FIXME ("create updown for yearselection\n");
1189 if (hit
== MCHT_TODAYLINK
) {
1190 FIXME ("set currentday\n");
1192 if (hit
== MCHT_CALENDARDATE
) {
1193 SYSTEMTIME selArray
[2];
1197 nmsc
.nmhdr
.hwndFrom
= hwnd
;
1198 nmsc
.nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
1199 nmsc
.nmhdr
.code
= MCN_SELCHANGE
;
1200 MONTHCAL_CopyTime (&nmsc
.stSelStart
, &infoPtr
->minSel
);
1201 MONTHCAL_CopyTime (&nmsc
.stSelEnd
, &infoPtr
->maxSel
);
1203 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1204 (WPARAM
)nmsc
.nmhdr
.idFrom
, (LPARAM
)&nmsc
);
1206 MONTHCAL_CopyTime (&ht
.st
, &selArray
[0]);
1207 MONTHCAL_CopyTime (&ht
.st
, &selArray
[1]);
1208 MONTHCAL_SetSelRange (hwnd
,0,(LPARAM
) &selArray
);
1210 infoPtr
->firstSelDay
=ht
.st
.wDay
;
1211 infoPtr
->curSelDay
=ht
.st
.wDay
;
1212 infoPtr
->status
=MC_SEL_LBUTDOWN
;
1215 MONTHCAL_Refresh (hwnd
,hdc
);
1216 ReleaseDC (hwnd
,hdc
);
1221 MONTHCAL_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1224 MONTHCAL_INFO
*infoPtr
= MONTHCAL_GetInfoPtr (hwnd
);
1231 if (infoPtr
->status
& MC_NEXTPRESSED
)
1232 KillTimer (hwnd
, MC_NEXTMONTHTIMER
);
1233 if (infoPtr
->status
& MC_PREVPRESSED
)
1234 KillTimer (hwnd
, MC_PREVMONTHTIMER
);
1235 infoPtr
->status
=MC_SEL_LBUTUP
;
1236 infoPtr
->curSelDay
=0;
1238 nmhdr
.hwndFrom
= hwnd
;
1239 nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
1240 nmhdr
.code
= NM_RELEASEDCAPTURE
;
1241 TRACE ("Sent notification from %x to %x\n", hwnd
, GetParent (hwnd
));
1243 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1244 (WPARAM
)nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
1246 nmsc
.nmhdr
.hwndFrom
= hwnd
;
1247 nmsc
.nmhdr
.idFrom
= GetWindowLongA( hwnd
, GWL_ID
);
1248 nmsc
.nmhdr
.code
= MCN_SELECT
;
1249 MONTHCAL_CopyTime (&nmsc
.stSelStart
, &infoPtr
->minSel
);
1250 MONTHCAL_CopyTime (&nmsc
.stSelEnd
, &infoPtr
->maxSel
);
1252 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1253 (WPARAM
)nmsc
.nmhdr
.idFrom
, (LPARAM
)&nmsc
);
1256 MONTHCAL_Refresh (hwnd
,hdc
);
1257 ReleaseDC (hwnd
,hdc
);
1263 MONTHCAL_Timer (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1266 MONTHCAL_INFO
*infoPtr
= MONTHCAL_GetInfoPtr (hwnd
);
1269 TRACE(" %d\n",wParam
);
1270 if (!infoPtr
) return FALSE
;
1274 case MC_NEXTMONTHTIMER
:
1275 MONTHCAL_GoToNextMonth (hwnd
, infoPtr
);
1277 case MC_PREVMONTHTIMER
:
1278 MONTHCAL_GoToPrevMonth (hwnd
, infoPtr
);
1281 ERR("got unknown timer\n");
1284 MONTHCAL_Refresh (hwnd
,hdc
);
1285 ReleaseDC (hwnd
,hdc
);
1292 MONTHCAL_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1294 MONTHCAL_INFO
*infoPtr
= MONTHCAL_GetInfoPtr (hwnd
);
1300 if (!(infoPtr
->status
& MC_SEL_LBUTDOWN
)) return 0;
1302 ht
.pt
.x
=LOWORD(lParam
);
1303 ht
.pt
.y
=HIWORD(lParam
);
1305 hit
=MONTHCAL_HitTest (hwnd
, (LPARAM
) &ht
);
1307 /* not on the calendar date numbers? bail out */
1308 TRACE ("hit:%x\n",hit
);
1309 if ((hit
& MCHT_CALENDARDATE
) !=MCHT_CALENDARDATE
) return 0;
1312 infoPtr
->curSelDay
=selday
;
1313 MONTHCAL_CalcPosFromDay (infoPtr
,selday
,ht
.st
.wMonth
,&r
);
1315 if ( GetWindowLongA( hwnd
, GWL_STYLE
) & MCS_MULTISELECT
) {
1316 SYSTEMTIME selArray
[2];
1319 MONTHCAL_GetSelRange (hwnd
,0,(LPARAM
) &selArray
);
1321 if (infoPtr
->firstSelDay
==selArray
[0].wDay
) i
=1;
1322 TRACE ("oldRange:%d %d %d %d\n",infoPtr
->firstSelDay
,selArray
[0].wDay
,selArray
[1].wDay
,i
);
1323 if (infoPtr
->firstSelDay
==selArray
[1].wDay
) {
1324 /* 1st time we get here: selArray[0]=selArray[1]) */
1325 /* if we're still at the first selected date, return */
1326 if (infoPtr
->firstSelDay
==selday
) goto done
;
1328 if (selday
<infoPtr
->firstSelDay
) i
=0;
1331 if (abs(infoPtr
->firstSelDay
- selday
) >= infoPtr
->maxSelCount
) {
1332 if (selday
>infoPtr
->firstSelDay
)
1333 selday
=infoPtr
->firstSelDay
+infoPtr
->maxSelCount
;
1335 selday
=infoPtr
->firstSelDay
-infoPtr
->maxSelCount
;
1338 if (selArray
[i
].wDay
!=selday
) {
1340 TRACE ("newRange:%d %d %d %d\n",infoPtr
->firstSelDay
,selArray
[0].wDay
,selArray
[1].wDay
,i
);
1342 selArray
[i
].wDay
=selday
;
1345 if (selArray
[0].wDay
>selArray
[1].wDay
) {
1347 tempday
=selArray
[1].wDay
;
1348 selArray
[1].wDay
=selArray
[0].wDay
;
1349 selArray
[0].wDay
=tempday
;
1352 MONTHCAL_SetSelRange (hwnd
,0,(LPARAM
) &selArray
);
1359 MONTHCAL_Refresh (hwnd
, hdc
);
1360 ReleaseDC (hwnd
, hdc
);
1366 MONTHCAL_Paint (HWND hwnd
, WPARAM wParam
)
1371 hdc
= wParam
==0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
1372 MONTHCAL_Refresh (hwnd
, hdc
);
1374 EndPaint (hwnd
, &ps
);
1379 MONTHCAL_KillFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1386 MONTHCAL_Refresh (hwnd
, hdc
);
1387 ReleaseDC (hwnd
, hdc
);
1388 InvalidateRect (hwnd
, NULL
, TRUE
);
1395 MONTHCAL_SetFocus (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1402 MONTHCAL_Refresh (hwnd
, hdc
);
1403 ReleaseDC (hwnd
, hdc
);
1409 /* FIXME: check whether dateMin/dateMax need to be adjusted. */
1413 MONTHCAL_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1415 MONTHCAL_INFO
*infoPtr
;
1418 /* allocate memory for info structure */
1419 infoPtr
= (MONTHCAL_INFO
*)COMCTL32_Alloc (sizeof(MONTHCAL_INFO
));
1420 SetWindowLongA (hwnd
, 0, (DWORD
)infoPtr
);
1422 if (infoPtr
== NULL
) {
1423 ERR ( "could not allocate info memory!\n");
1426 if ((MONTHCAL_INFO
*) GetWindowLongA( hwnd
, 0) != infoPtr
) {
1427 ERR ( "pointer assignment error!\n");
1432 infoPtr
->hFont
=GetStockObject(DEFAULT_GUI_FONT
);
1433 GetObjectA (infoPtr
->hFont
, sizeof (LOGFONTA
), &logFont
);
1434 logFont
.lfWeight
=FW_BOLD
;
1435 infoPtr
->hBoldFont
= CreateFontIndirectA (&logFont
);
1437 /* initialize info structure */
1438 /* FIXME: calculate systemtime ->> localtime (substract timezoneinfo) */
1440 GetSystemTime (&infoPtr
->todaysDate
);
1441 infoPtr
->firstDay
= 0;
1442 infoPtr
->currentMonth
= infoPtr
->todaysDate
.wMonth
;
1443 infoPtr
->currentYear
= infoPtr
->todaysDate
.wYear
;
1444 MONTHCAL_CopyTime (&infoPtr
->todaysDate
,&infoPtr
->minDate
);
1445 MONTHCAL_CopyTime (&infoPtr
->todaysDate
,&infoPtr
->maxDate
);
1446 infoPtr
->maxSelCount
=6;
1447 infoPtr
->monthRange
=3;
1448 infoPtr
->monthdayState
=COMCTL32_Alloc
1449 (infoPtr
->monthRange
*sizeof(MONTHDAYSTATE
));
1450 infoPtr
->titlebk
= GetSysColor (COLOR_GRAYTEXT
);
1451 infoPtr
->titletxt
= GetSysColor (COLOR_WINDOW
);
1452 infoPtr
->monthbk
= GetSysColor (COLOR_WINDOW
);
1453 infoPtr
->trailingtxt
= GetSysColor (COLOR_GRAYTEXT
);
1454 infoPtr
->bk
= GetSysColor (COLOR_WINDOW
);
1455 infoPtr
->txt
= GetSysColor (COLOR_WINDOWTEXT
);
1462 MONTHCAL_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1464 MONTHCAL_INFO
*infoPtr
= MONTHCAL_GetInfoPtr (hwnd
);
1466 /* free month calendar info data */
1467 COMCTL32_Free (infoPtr
);
1474 static LRESULT WINAPI
1475 MONTHCAL_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1482 return MONTHCAL_GetCurSel (hwnd
, wParam
, lParam
);
1485 return MONTHCAL_SetCurSel (hwnd
, wParam
, lParam
);
1487 case MCM_GETMAXSELCOUNT
:
1488 return MONTHCAL_GetMaxSelCount (hwnd
, wParam
, lParam
);
1490 case MCM_SETMAXSELCOUNT
:
1491 return MONTHCAL_SetMaxSelCount (hwnd
, wParam
, lParam
);
1493 case MCM_GETSELRANGE
:
1494 return MONTHCAL_GetSelRange (hwnd
, wParam
, lParam
);
1496 case MCM_SETSELRANGE
:
1497 return MONTHCAL_SetSelRange (hwnd
, wParam
, lParam
);
1499 case MCM_GETMONTHRANGE
:
1500 return MONTHCAL_GetMonthRange (hwnd
, wParam
, lParam
);
1502 case MCM_SETDAYSTATE
:
1503 return MONTHCAL_SetDayState (hwnd
, wParam
, lParam
);
1505 case MCM_GETMINREQRECT
:
1506 return MONTHCAL_GetMinReqRect (hwnd
, wParam
, lParam
);
1509 return MONTHCAL_GetColor (hwnd
, wParam
, lParam
);
1512 return MONTHCAL_SetColor (hwnd
, wParam
, lParam
);
1515 return MONTHCAL_GetToday (hwnd
, wParam
, lParam
);
1518 return MONTHCAL_SetToday (hwnd
, wParam
, lParam
);
1521 return MONTHCAL_HitTest (hwnd
,lParam
);
1523 case MCM_GETFIRSTDAYOFWEEK
:
1524 return MONTHCAL_GetFirstDayOfWeek (hwnd
, wParam
, lParam
);
1526 case MCM_SETFIRSTDAYOFWEEK
:
1527 return MONTHCAL_SetFirstDayOfWeek (hwnd
, wParam
, lParam
);
1530 return MONTHCAL_GetRange (hwnd
, wParam
, lParam
);
1533 return MONTHCAL_SetRange (hwnd
, wParam
, lParam
);
1535 case MCM_GETMONTHDELTA
:
1536 return MONTHCAL_GetMonthDelta (hwnd
, wParam
, lParam
);
1538 case MCM_SETMONTHDELTA
:
1539 return MONTHCAL_SetMonthDelta (hwnd
, wParam
, lParam
);
1541 case MCM_GETMAXTODAYWIDTH
:
1542 return MONTHCAL_GetMaxTodayWidth (hwnd
);
1545 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1548 return MONTHCAL_KillFocus (hwnd
, wParam
, lParam
);
1550 case WM_LBUTTONDOWN
:
1551 return MONTHCAL_LButtonDown (hwnd
, wParam
, lParam
);
1554 return MONTHCAL_MouseMove (hwnd
, wParam
, lParam
);
1557 return MONTHCAL_LButtonUp (hwnd
, wParam
, lParam
);
1560 return MONTHCAL_Paint (hwnd
, wParam
);
1563 return MONTHCAL_SetFocus (hwnd
, wParam
, lParam
);
1566 return MONTHCAL_Create (hwnd
, wParam
, lParam
);
1569 return MONTHCAL_Timer (hwnd
, wParam
, lParam
);
1572 return MONTHCAL_Destroy (hwnd
, wParam
, lParam
);
1575 if (uMsg
>= WM_USER
)
1576 ERR ( "unknown msg %04x wp=%08x lp=%08lx\n",
1577 uMsg
, wParam
, lParam
);
1578 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
1585 MONTHCAL_Register (void)
1589 if (GlobalFindAtomA (MONTHCAL_CLASSA
)) return;
1591 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
1592 wndClass
.style
= CS_GLOBALCLASS
;
1593 wndClass
.lpfnWndProc
= (WNDPROC
)MONTHCAL_WindowProc
;
1594 wndClass
.cbClsExtra
= 0;
1595 wndClass
.cbWndExtra
= sizeof(MONTHCAL_INFO
*);
1596 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
1597 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
1598 wndClass
.lpszClassName
= MONTHCAL_CLASSA
;
1600 RegisterClassA (&wndClass
);
1605 MONTHCAL_Unregister (void)
1607 if (GlobalFindAtomA (MONTHCAL_CLASSA
))
1608 UnregisterClassA (MONTHCAL_CLASSA
, (HINSTANCE
)NULL
);