- new interface declaration for IShellfolder2
[wine/dcerpc.git] / dlls / comctl32 / monthcal.c
blobd2a09b172cd2f9ace37f3ad46143446c1881fbf8
2 /* Month calendar control
6 * Copyright 1998, 1999 Eric Kohl (ekohl@abo.rhein-zeitung.de)
7 * Copyright 1999 Alex Priem (alexp@sci.kun.nl)
9 * TODO:
10 * - Notifications.
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.
20 #include "winbase.h"
21 #include "winuser.h"
22 #include "wingdi.h"
23 #include "win.h"
24 #include "winnls.h"
25 #include "commctrl.h"
26 #include "comctl32.h"
27 #include "monthcal.h"
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
34 * defined here */
36 extern int mdays[];
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))
48 /* helper functions
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;
65 return TRUE;
68 void MONTHCAL_CopyTime (const SYSTEMTIME *from, SYSTEMTIME *to)
71 to->wYear=from->wYear;
72 to->wMonth=from->wMonth;
73 to->wDayOfWeek=from->wDayOfWeek;
74 to->wDay=from->wDay;
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.
86 0=Monday.
90 int MONTHCAL_CalculateDayOfWeek (DWORD day, DWORD month, DWORD year)
93 year -= month < 3;
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);
110 return retval;
114 static void MONTHCAL_CalcDayXY (MONTHCAL_INFO *infoPtr, int day, int month,
115 int *x, int *y)
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;
125 return;
127 if (month < infoPtr->currentMonth) {
128 prevMonth=month - 1;
129 if (prevMonth==0) prevMonth=11;
130 *x=(mdays[prevMonth]-firstDay) & 7;
131 *y=0;
134 *y=mdays[month] / 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)
153 int x,y;
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 );
167 POINT points[7];
168 int x,y;
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;
176 points[0].x = x;
177 points[0].y = y-0.25*infoPtr->textHeight;
178 points[1].x = x-1.0*infoPtr->textWidth;
179 points[1].y = y;
180 points[2].x = x;
181 points[2].y = y+0.6*infoPtr->textHeight;
182 points[3].x = x+0.5*infoPtr->textWidth;
183 points[3].y = y;
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)
205 char buf[10];
206 RECT r;
207 static int haveBoldFont,haveSelectedDay=FALSE;
208 HBRUSH hbr;
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)) {
223 HRGN hrgn;
224 RECT r2;
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;
235 r2.top = r.top;
236 r2.right = r.left+0.5*infoPtr->textWidth;
237 r2.bottom = r.bottom;
238 if (haveSelectedDay) FillRect (hdc,&r2,hbr);
239 haveSelectedDay=TRUE;
240 } else {
241 haveSelectedDay=FALSE;
246 /* need to add some code for multiple selections */
248 if ((bold) && (!haveBoldFont)) {
249 SelectObject (hdc, infoPtr->hBoldFont);
250 haveBoldFont=TRUE;
252 if ((!bold) && (haveBoldFont)) {
253 SelectObject (hdc, infoPtr->hFont);
254 haveBoldFont=FALSE;
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 );
272 r.left+=2;
273 r.right-=2;
274 r.top-=1;
275 r.bottom+=1;
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;
303 SIZE size;
304 HBRUSH hbr;
305 HFONT currentFont;
306 TEXTMETRICA tm;
307 /* LOGFONTA logFont; */
308 char buf[20],*thisMonthtxt;
309 COLORREF oldTextColor,oldBkColor;
310 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
311 BOOL prssed;
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);
338 DeleteObject (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;
353 /* draw header */
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;
368 prssed=FALSE;
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);
405 else
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;
419 i=infoPtr->firstDay;
421 for (j=0; j<7; j++) {
422 DrawTextA ( hdc, daytxt[i], strlen(daytxt[i]), days,
423 DT_CENTER | DT_VCENTER | DT_SINGLELINE );
424 i++;
425 if (i>7) i-=7;
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 */
436 prevmonth->left=0;
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;
443 mask=1<<(day-1);
445 i=0;
446 m=0;
447 while (day<=mdays[prevMonth]) {
448 MONTHCAL_DrawDay (hdc, infoPtr, day, prevMonth, i, 0,
449 infoPtr->monthdayState[m] & mask);
450 mask<<=1;
451 day++;
452 i++;
455 prevmonth->right = prevmonth->left+i*textWidth;
456 prevmonth->top = days->bottom;
457 prevmonth->bottom= prevmonth->top + textHeight;
459 /* draw `current' month */
461 day=1;
462 infoPtr->firstDayplace=i;
463 SetTextColor(hdc, infoPtr->txt);
464 m++;
465 mask=1;
466 while (i<7) {
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);
472 mask<<=1;
473 day++;
474 i++;
477 j=1;
478 i=0;
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);
485 mask<<=1;
486 day++;
487 i++;
488 if (i>6) {
489 i=0;
490 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;
508 day=1;
509 m++;
510 mask=1;
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);
515 mask<<=1;
516 day++;
517 i++;
518 if (i==7) {
519 i=0;
520 j++;
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)) {
531 int offset=0;
532 if (!( dwStyle & MCS_NOTODAYCIRCLE)) {
533 MONTHCAL_CircleDay (hdc, infoPtr, 0, 6);
534 offset+=textWidth;
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*/
550 weeknums->left = 0;
551 weeknums->right = textWidth;
552 weeknums->top = days->bottom + 2;
553 weeknums->bottom = days->bottom + 2 + textHeight;
555 weeknum=0;
556 for (i=0; i<infoPtr->currentMonth-1; i++)
557 weeknum+=mdays[i];
559 weeknum/=7;
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);
581 static LRESULT
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;
597 return TRUE;
600 static LRESULT
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:
610 return infoPtr->bk;
611 case MCSC_TEXT:
612 return infoPtr->txt;
613 case MCSC_TITLEBK:
614 return infoPtr->titlebk;
615 case MCSC_TITLETEXT:
616 return infoPtr->titletxt;
617 case MCSC_MONTHBK:
618 return infoPtr->monthbk;
619 case MCSC_TRAILINGTEXT:
620 return infoPtr->trailingtxt;
623 return -1;
626 static LRESULT
627 MONTHCAL_SetColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
630 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
631 int prev=-1;
633 TRACE ("%x %lx\n",wParam,lParam);
635 switch ((int)wParam) {
636 case MCSC_BACKGROUND:
637 prev=infoPtr->bk;
638 infoPtr->bk=(COLORREF) lParam;
639 break;
640 case MCSC_TEXT:
641 prev=infoPtr->txt;
642 infoPtr->txt=(COLORREF) lParam;
643 break;
644 case MCSC_TITLEBK:
645 prev=infoPtr->titlebk;
646 infoPtr->titlebk=(COLORREF) lParam;
647 break;
648 case MCSC_TITLETEXT:
649 prev=infoPtr->titletxt;
650 infoPtr->titletxt=(COLORREF) lParam;
651 break;
652 case MCSC_MONTHBK:
653 prev=infoPtr->monthbk;
654 infoPtr->monthbk=(COLORREF) lParam;
655 break;
656 case MCSC_TRAILINGTEXT:
657 prev=infoPtr->trailingtxt;
658 infoPtr->trailingtxt=(COLORREF) lParam;
659 break;
662 return prev;
665 static LRESULT
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;
677 static LRESULT
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;
687 return prev;
692 static LRESULT
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 */
702 static LRESULT
703 MONTHCAL_SetFirstDayOfWeek (HWND hwnd, WPARAM wParam, LPARAM lParam)
706 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
707 int prev=infoPtr->firstDay;
708 char buf[40];
709 int day;
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,
716 buf, sizeof(buf));
717 TRACE ("%s %d\n",buf,strlen(buf));
718 if ((sscanf(buf,"%d",&day)==1) && (infoPtr->firstDay!=day))
719 infoPtr->firstDay|=HIWORD(TRUE);
722 return prev;
727 /* FIXME: fill this in */
729 static LRESULT
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;
739 static LRESULT
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
749 * copied?
750 * FIXME: check whether MCM_GETMONTHRANGE shows correct result after
751 * adjusting range with MCM_SETRANGE
754 static LRESULT
755 MONTHCAL_SetRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
757 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
758 SYSTEMTIME lprgSysTimeArray[1];
759 int prev;
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;
767 } else {
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;
776 } else {
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));
788 return 1;
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?
797 static LRESULT
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;
813 static LRESULT
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];
826 return 1;
829 static LRESULT
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);
840 return TRUE;
844 /* FIXME: if the specified date is not visible, make it visible */
845 /* FIXME: redraw? */
847 static LRESULT
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);
862 return TRUE;
865 static LRESULT
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;
874 static LRESULT
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;
884 return TRUE;
888 static LRESULT
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);
904 return TRUE;
907 return FALSE;
910 static LRESULT
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);
926 return TRUE;
929 return FALSE;
935 static LRESULT
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);
947 return TRUE;
951 static LRESULT
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);
963 return TRUE;
969 static LRESULT
970 MONTHCAL_HitTest (HWND hwnd, LPARAM lParam)
972 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
973 PMCHITTESTINFO lpht=(PMCHITTESTINFO) lParam;
974 UINT x,y;
975 DWORD retval;
977 x=lpht->pt.x;
978 y=lpht->pt.y;
979 retval=MCHT_NOWHERE;
982 /* are we in the header? */
984 if (PtInRect (&infoPtr->title, lpht->pt)) {
986 if (PtInRect (&infoPtr->titlebtnprev, lpht->pt)) {
987 retval=MCHT_TITLEBTNPREV;
988 goto done;
990 if (PtInRect (&infoPtr->titlebtnnext, lpht->pt)) {
991 retval=MCHT_TITLEBTNNEXT;
992 goto done;
994 if (PtInRect (&infoPtr->titlemonth, lpht->pt)) {
995 retval=MCHT_TITLEMONTH;
996 goto done;
998 if (PtInRect (&infoPtr->titleyear, lpht->pt)) {
999 retval=MCHT_TITLEYEAR;
1000 goto done;
1002 retval=MCHT_TITLE;
1003 goto done;
1006 if (PtInRect (&infoPtr->days, lpht->pt)) {
1007 retval=MCHT_CALENDARDAY; /* FIXME: find out which day we're on */
1008 goto done;
1010 if (PtInRect (&infoPtr->weeknums, lpht->pt)) {
1011 retval=MCHT_CALENDARWEEKNUM;/* FIXME: find out which day we're on */
1012 goto done;
1014 if (PtInRect (&infoPtr->prevmonth, lpht->pt)) {
1015 retval=MCHT_CALENDARDATEPREV;
1016 goto done;
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;
1022 goto done;
1026 if (PtInRect (&infoPtr->today, lpht->pt)) {
1027 retval=MCHT_TODAYLINK;
1028 goto done;
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;
1053 goto done;
1057 /* Hit nothing special? What's left must be background :-) */
1059 retval=MCHT_CALENDARBK;
1060 done:
1061 lpht->uHit=retval;
1062 return retval;
1067 static void MONTHCAL_GoToNextMonth (HWND hwnd, MONTHCAL_INFO *infoPtr)
1069 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1071 TRACE ("\n");
1073 infoPtr->currentMonth++;
1074 if (infoPtr->currentMonth>12) {
1075 infoPtr->currentYear++;
1076 infoPtr->currentMonth=1;
1079 if (dwStyle & MCS_DAYSTATE) {
1080 NMDAYSTATE nmds;
1081 int i;
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);
1103 TRACE ("\n");
1105 infoPtr->currentMonth--;
1106 if (infoPtr->currentMonth<1) {
1107 infoPtr->currentYear--;
1108 infoPtr->currentMonth=12;
1111 if (dwStyle & MCS_DAYSTATE) {
1112 NMDAYSTATE nmds;
1113 int i;
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];
1130 static LRESULT
1131 MONTHCAL_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1134 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr (hwnd);
1135 MCHITTESTINFO ht;
1136 HDC hdc;
1137 DWORD hit;
1138 HMENU hMenu;
1139 HWND retval;
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);
1148 hdc=GetDC (hwnd);
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 );
1164 if (!hrsrc) {
1165 TRACE ("returning zero\n");
1166 return 0;
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,
1181 0,0,100,220,
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];
1194 NMSELCHANGE nmsc;
1196 TRACE ("\n");
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);
1217 return 0;
1220 static LRESULT
1221 MONTHCAL_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1224 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr (hwnd);
1225 NMSELCHANGE nmsc;
1226 NMHDR nmhdr;
1227 HDC hdc;
1229 TRACE ("\n");
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);
1255 hdc=GetDC (hwnd);
1256 MONTHCAL_Refresh (hwnd,hdc);
1257 ReleaseDC (hwnd,hdc);
1259 return 0;
1262 static LRESULT
1263 MONTHCAL_Timer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1266 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr (hwnd);
1267 HDC hdc;
1269 TRACE(" %d\n",wParam);
1270 if (!infoPtr) return FALSE;
1272 hdc=GetDC (hwnd);
1273 switch (wParam) {
1274 case MC_NEXTMONTHTIMER:
1275 MONTHCAL_GoToNextMonth (hwnd, infoPtr);
1276 break;
1277 case MC_PREVMONTHTIMER:
1278 MONTHCAL_GoToPrevMonth (hwnd, infoPtr);
1279 break;
1280 default:
1281 ERR("got unknown timer\n");
1284 MONTHCAL_Refresh (hwnd,hdc);
1285 ReleaseDC (hwnd,hdc);
1286 return 0;
1291 static LRESULT
1292 MONTHCAL_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1294 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr (hwnd);
1295 MCHITTESTINFO ht;
1296 HDC hdc;
1297 int selday,hit;
1298 RECT r;
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;
1311 selday=ht.st.wDay;
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];
1317 int i;
1319 MONTHCAL_GetSelRange (hwnd,0,(LPARAM) &selArray);
1320 i=0;
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;
1334 else
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) {
1346 DWORD tempday;
1347 tempday=selArray[1].wDay;
1348 selArray[1].wDay=selArray[0].wDay;
1349 selArray[0].wDay=tempday;
1352 MONTHCAL_SetSelRange (hwnd,0,(LPARAM) &selArray);
1356 done:
1358 hdc=GetDC (hwnd);
1359 MONTHCAL_Refresh (hwnd, hdc);
1360 ReleaseDC (hwnd, hdc);
1362 return 0;
1365 static LRESULT
1366 MONTHCAL_Paint (HWND hwnd, WPARAM wParam)
1368 HDC hdc;
1369 PAINTSTRUCT ps;
1371 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1372 MONTHCAL_Refresh (hwnd, hdc);
1373 if(!wParam)
1374 EndPaint (hwnd, &ps);
1375 return 0;
1378 static LRESULT
1379 MONTHCAL_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
1381 HDC hdc;
1383 TRACE ("\n");
1385 hdc = GetDC (hwnd);
1386 MONTHCAL_Refresh (hwnd, hdc);
1387 ReleaseDC (hwnd, hdc);
1388 InvalidateRect (hwnd, NULL, TRUE);
1390 return 0;
1394 static LRESULT
1395 MONTHCAL_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
1397 HDC hdc;
1399 TRACE ("\n");
1401 hdc = GetDC (hwnd);
1402 MONTHCAL_Refresh (hwnd, hdc);
1403 ReleaseDC (hwnd, hdc);
1405 return 0;
1409 /* FIXME: check whether dateMin/dateMax need to be adjusted. */
1412 static LRESULT
1413 MONTHCAL_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1415 MONTHCAL_INFO *infoPtr;
1416 LOGFONTA logFont;
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");
1424 return 0;
1426 if ((MONTHCAL_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
1427 ERR ( "pointer assignment error!\n");
1428 return 0;
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);
1457 return 0;
1461 static LRESULT
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);
1469 return 0;
1474 static LRESULT WINAPI
1475 MONTHCAL_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1478 switch (uMsg)
1481 case MCM_GETCURSEL:
1482 return MONTHCAL_GetCurSel (hwnd, wParam, lParam);
1484 case MCM_SETCURSEL:
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);
1508 case MCM_GETCOLOR:
1509 return MONTHCAL_GetColor (hwnd, wParam, lParam);
1511 case MCM_SETCOLOR:
1512 return MONTHCAL_SetColor (hwnd, wParam, lParam);
1514 case MCM_GETTODAY:
1515 return MONTHCAL_GetToday (hwnd, wParam, lParam);
1517 case MCM_SETTODAY:
1518 return MONTHCAL_SetToday (hwnd, wParam, lParam);
1520 case MCM_HITTEST:
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);
1529 case MCM_GETRANGE:
1530 return MONTHCAL_GetRange (hwnd, wParam, lParam);
1532 case MCM_SETRANGE:
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);
1544 case WM_GETDLGCODE:
1545 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1547 case WM_KILLFOCUS:
1548 return MONTHCAL_KillFocus (hwnd, wParam, lParam);
1550 case WM_LBUTTONDOWN:
1551 return MONTHCAL_LButtonDown (hwnd, wParam, lParam);
1553 case WM_MOUSEMOVE:
1554 return MONTHCAL_MouseMove (hwnd, wParam, lParam);
1556 case WM_LBUTTONUP:
1557 return MONTHCAL_LButtonUp (hwnd, wParam, lParam);
1559 case WM_PAINT:
1560 return MONTHCAL_Paint (hwnd, wParam);
1562 case WM_SETFOCUS:
1563 return MONTHCAL_SetFocus (hwnd, wParam, lParam);
1565 case WM_CREATE:
1566 return MONTHCAL_Create (hwnd, wParam, lParam);
1568 case WM_TIMER:
1569 return MONTHCAL_Timer (hwnd, wParam, lParam);
1571 case WM_DESTROY:
1572 return MONTHCAL_Destroy (hwnd, wParam, lParam);
1574 default:
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);
1580 return 0;
1584 void
1585 MONTHCAL_Register (void)
1587 WNDCLASSA wndClass;
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);
1604 void
1605 MONTHCAL_Unregister (void)
1607 if (GlobalFindAtomA (MONTHCAL_CLASSA))
1608 UnregisterClassA (MONTHCAL_CLASSA, (HINSTANCE)NULL);