source: trunk/src/comctl32/monthcal.c@ 1036

Last change on this file since 1036 was 496, checked in by cbratschi, 26 years ago

wine-990731 update

File size: 48.0 KB
Line 
1
2/* Month calendar control
3
4
5 *
6 * Copyright 1998, 1999 Eric Kohl (ekohl@abo.rhein-zeitung.de)
7 * Copyright 1999 Alex Priem (alexp@sci.kun.nl)
8 * Copyright 1999 Christoph Bratschi
9 *
10 * TODO:
11 * - Notifications.
12 *
13 *
14 * FIXME: refresh should ask for rect of required length. (?)
15 * FIXME: we refresh to often; especially in LButtonDown/MouseMove.
16 * FIXME: handle resources better (doesn't work now); also take care
17 of internationalization.
18 * FIXME: keyboard handling.
19 */
20
21#include "winbase.h"
22#include "win.h"
23#include "commctrl.h"
24#include "comctl32.h"
25#include "monthcal.h"
26#include "winnls.h"
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30
31//DEFAULT_DEBUG_CHANNEL(monthcal)
32
33/* take #days/month from ole/parsedt.c;
34 * we want full month-names, and abbreviated weekdays, so these are
35 * defined here */
36
37#define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)GetWindowLongA (hwnd, 0))
38
39/* helper functions
40 * MONTHCAL_ValidateTime: is time a valid date/time combo?
41 */
42
43int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
44
45int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
46
47static char *daytxt[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
48
49static char *monthtxt[] = {"January", "February", "March", "April", "May",
50 "June", "July", "August", "September", "October",
51 "November", "December"};
52
53/* CHECKME: all these validations OK? */
54
55static int MONTHCAL_ValidateTime (SYSTEMTIME time)
56
57{
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;
66}
67
68void MONTHCAL_CopyTime (const SYSTEMTIME *from, SYSTEMTIME *to)
69
70{
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;
79}
80
81
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.
87*/
88
89
90int MONTHCAL_CalculateDayOfWeek (DWORD day, DWORD month, DWORD year)
91
92{
93 year -= month < 3;
94 return (year + year/4 - year/100 + year/400 +
95 DayOfWeekTable[month-1] + day - 1 ) % 7;
96}
97
98
99static int MONTHCAL_CalcDayFromPos (MONTHCAL_INFO *infoPtr, int x, int y)
100
101{
102 int daypos,weekpos,retval,firstDay;
103
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;
111}
112
113
114static void MONTHCAL_CalcDayXY (MONTHCAL_INFO *infoPtr, int day, int month,
115 int *x, int *y)
116
117{
118 int firstDay,prevMonth;
119
120 firstDay=MONTHCAL_CalculateDayOfWeek (1,infoPtr->currentMonth,infoPtr->currentYear);
121
122 if (month==infoPtr->currentMonth) {
123 *x=(day+firstDay) & 7;
124 *y=(day+firstDay-*x) / 7;
125 return;
126 }
127 if (month < infoPtr->currentMonth) {
128 prevMonth=month - 1;
129 if (prevMonth==0) prevMonth=11;
130 *x=(mdays[prevMonth]-firstDay) & 7;
131 *y=0;
132 }
133
134 *y=mdays[month] / 7;
135 *x=(day+firstDay+mdays[month]) & 7;
136}
137
138
139static void MONTHCAL_CalcDayRect (MONTHCAL_INFO *infoPtr, RECT *r, int x, int y)
140{
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;
146
147}
148
149static void MONTHCAL_CalcPosFromDay (MONTHCAL_INFO *infoPtr,
150 int day, int month, RECT *r)
151
152{
153 int x,y;
154
155 MONTHCAL_CalcDayXY (infoPtr, day, month, &x, &y);
156 MONTHCAL_CalcDayRect (infoPtr, r, x, y);
157}
158
159
160
161
162static void MONTHCAL_CircleDay (HDC hdc, MONTHCAL_INFO *infoPtr, int i, int j)
163
164{
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;
169
170 /* use prevmonth to calculate position because it contains the extra width
171 * from MCS_WEEKNUMBERS
172 */
173
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;
190
191 PolyBezier (hdc,points,4);
192 PolyBezier (hdc,points+3,4);
193 DeleteObject (hRedPen);
194 SelectObject (hdc, hOldPen2);
195}
196
197
198
199
200
201static void MONTHCAL_DrawDay (HDC hdc, MONTHCAL_INFO *infoPtr,
202 int day, int month, int x, int y, int bold)
203
204{
205 char buf[10];
206 RECT r;
207 static int haveBoldFont,haveSelectedDay=FALSE;
208 HBRUSH hbr;
209 COLORREF oldCol,oldBk;
210
211 sprintf (buf,"%d",day);
212
213
214
215/* No need to check styles: when selection is not valid, it is set to zero.
216 * 1<day<31, so evertyhing's OK.
217 */
218
219 MONTHCAL_CalcDayRect (infoPtr, &r, x, y);
220
221 if ((day>=infoPtr->minSel.wDay) && (day<=infoPtr->maxSel.wDay)
222 && (month==infoPtr->currentMonth)) {
223 HRGN hrgn;
224 RECT r2;
225
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);
233
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;
242 }
243
244
245
246/* need to add some code for multiple selections */
247
248 if ((bold) && (!haveBoldFont)) {
249 SelectObject (hdc, infoPtr->hBoldFont);
250 haveBoldFont=TRUE;
251 }
252 if ((!bold) && (haveBoldFont)) {
253 SelectObject (hdc, infoPtr->hFont);
254 haveBoldFont=FALSE;
255 }
256
257
258
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);
264 }
265
266 if ((day==infoPtr->curSelDay) && (month==infoPtr->currentMonth)) {
267 HPEN hNewPen, hOldPen;
268
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 );
278 }
279}
280
281
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 */
285
286static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
287
288{
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;
312
313
314 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_WINDOWTEXT));
315
316 currentFont = SelectObject (hdc, infoPtr->hFont);
317
318 /* FIXME: need a way to determine current font, without setting it */
319/*
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);
326 }
327*/
328
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;
333
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);
339
340/* calculate whole client area & title area */
341
342 infoPtr->rcClient.right=7*infoPtr->textWidth;
343 if (dwStyle & MCS_WEEKNUMBERS)
344 infoPtr->rcClient.right+=infoPtr->textWidth;
345
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;
351
352
353/* draw header */
354
355 hbr = CreateSolidBrush (infoPtr->titlebk);
356 FillRect (hdc, title, hbr);
357
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;
369
370 if (!(infoPtr->status & MC_PREVPRESSED))
371 DrawFrameControl(hdc, prev, DFC_SCROLL,
372 DFCS_SCROLLLEFT | (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
373
374 if (!(infoPtr->status & MC_NEXTPRESSED))
375 DrawFrameControl(hdc, next, DFC_SCROLL,
376 DFCS_SCROLLRIGHT | (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
377
378 oldBkColor=SetBkColor (hdc,infoPtr->titlebk);
379 SetTextColor(hdc, infoPtr->titletxt);
380 SelectObject (hdc, infoPtr->hBoldFont);
381
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);
387
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)
391 */
392
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;
399
400/* draw line under day abbreviatons */
401
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);
408
409/* draw day abbreviations */
410
411 SetBkColor (hdc, infoPtr->monthbk);
412 SetTextColor(hdc, infoPtr->trailingtxt);
413
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;
420
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;
428 }
429
430 days->left = rcClient->left + j;
431 if (dwStyle & MCS_WEEKNUMBERS) days->left+=textWidth;
432 days->right = rcClient->left + (j+1)*textWidth-2;
433
434/* draw day numbers; first, the previous month */
435
436 prevmonth->left=0;
437 if (dwStyle & MCS_WEEKNUMBERS) prevmonth->left=textWidth;
438
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);
444
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++;
453 }
454
455 prevmonth->right = prevmonth->left+i*textWidth;
456 prevmonth->top = days->bottom;
457 prevmonth->bottom= prevmonth->top + textHeight;
458
459/* draw `current' month */
460
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++;
475 }
476
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++;
491 }
492 }
493
494/* draw `next' month */
495
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.*/
500
501
502
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;
507
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++;
521 }
522 }
523 SetTextColor(hdc, infoPtr->txt);
524
525
526
527/* draw `today' date if style allows it, and draw a circle before today's
528 * date if necessairy */
529
530 if (!( dwStyle & MCS_NOTODAY)) {
531 int offset=0;
532 if (!( dwStyle & MCS_NOTODAYCIRCLE)) {
533 MONTHCAL_CircleDay (hdc, infoPtr, 0, 6);
534 offset+=textWidth;
535 }
536
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);
545 }
546
547 if (dwStyle & MCS_WEEKNUMBERS) {
548 /* display weeknumbers*/
549
550 weeknums->left = 0;
551 weeknums->right = textWidth;
552 weeknums->top = days->bottom + 2;
553 weeknums->bottom = days->bottom + 2 + textHeight;
554
555 weeknum=0;
556 for (i=0; i<infoPtr->currentMonth-1; i++)
557 weeknum+=mdays[i];
558
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;
566 }
567
568 MoveToEx (hdc, weeknums->right, days->bottom+5 , NULL);
569 LineTo (hdc, weeknums->right, weeknums->bottom-1.25*textHeight-5);
570
571 }
572
573 /* currentFont was font at entering Refresh */
574
575 SetBkColor (hdc, oldBkColor);
576 SelectObject (hdc, currentFont);
577 SetTextColor (hdc, oldTextColor);
578}
579
580
581static LRESULT
582MONTHCAL_GetMinReqRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
583
584{
585 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
586 LPRECT lpRect=(LPRECT) lParam;
587 //TRACE ("%x %lx\n",wParam,lParam);
588
589 /* validate parameters */
590
591 if ( (infoPtr==NULL) || (lpRect == NULL) ) return FALSE;
592
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;
598}
599
600static LRESULT
601MONTHCAL_GetColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
602
603{
604 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
605
606 //TRACE ("%x %lx\n",wParam,lParam);
607
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;
621 }
622
623 return -1;
624}
625
626static LRESULT
627MONTHCAL_SetColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
628
629{
630 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
631 int prev=-1;
632
633 //TRACE ("%x %lx\n",wParam,lParam);
634
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;
660 }
661
662 return prev;
663}
664
665static LRESULT
666MONTHCAL_GetMonthDelta (HWND hwnd, WPARAM wParam, LPARAM lParam)
667
668{
669 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
670
671 //TRACE ("%x %lx\n",wParam,lParam);
672
673 if (infoPtr->delta) return infoPtr->delta;
674 else return infoPtr->visible;
675}
676
677static LRESULT
678MONTHCAL_SetMonthDelta (HWND hwnd, WPARAM wParam, LPARAM lParam)
679
680{
681 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
682 int prev=infoPtr->delta;
683
684 //TRACE ("%x %lx\n",wParam,lParam);
685
686 infoPtr->delta=(int) wParam;
687 return prev;
688}
689
690
691
692static LRESULT
693MONTHCAL_GetFirstDayOfWeek (HWND hwnd, WPARAM wParam, LPARAM lParam)
694{
695 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
696
697 return infoPtr->firstDay;
698}
699
700/* FIXME: we need more error checking here */
701
702static LRESULT
703MONTHCAL_SetFirstDayOfWeek (HWND hwnd, WPARAM wParam, LPARAM lParam)
704
705{
706 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
707 int prev=infoPtr->firstDay;
708 char buf[40];
709 int day;
710
711 //TRACE ("%x %lx\n",wParam,lParam);
712
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);
720
721 }
722 return prev;
723}
724
725
726
727/* FIXME: fill this in */
728
729static LRESULT
730MONTHCAL_GetMonthRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
731{
732 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
733
734 //TRACE ("%x %lx\n",wParam,lParam);
735
736 return infoPtr->monthRange;
737}
738
739static LRESULT
740MONTHCAL_GetMaxTodayWidth (HWND hwnd)
741
742{
743 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
744
745 return (infoPtr->today.right-infoPtr->today.left);
746}
747
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
752 */
753
754static LRESULT
755MONTHCAL_SetRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
756{
757 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
758 SYSTEMTIME lprgSysTimeArray[1];
759 int prev;
760
761 //TRACE ("%x %lx\n",wParam,lParam);
762
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);
770 }
771 }
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);
779 }
780 }
781
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));
787
788 return 1;
789}
790
791
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?
795*/
796
797static LRESULT
798MONTHCAL_GetRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
799{
800 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
801 SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *) lParam;
802
803 /* validate parameters */
804
805 if ( (infoPtr==NULL) || (lprgSysTimeArray==NULL) ) return FALSE;
806
807 MONTHCAL_CopyTime (&infoPtr->maxDate,&lprgSysTimeArray[1]);
808 MONTHCAL_CopyTime (&infoPtr->minDate,&lprgSysTimeArray[0]);
809
810 return infoPtr->rangeValid;
811}
812
813static LRESULT
814MONTHCAL_SetDayState (HWND hwnd, WPARAM wParam, LPARAM lParam)
815
816{
817 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
818 int i,iMonths=(int) wParam;
819 MONTHDAYSTATE *dayStates=(LPMONTHDAYSTATE) lParam;
820
821 //TRACE ("%x %lx\n",wParam,lParam);
822 if (iMonths!=infoPtr->monthRange) return 0;
823
824 for (i=0; i<iMonths; i++)
825 infoPtr->monthdayState[i]=dayStates[i];
826 return 1;
827}
828
829static LRESULT
830MONTHCAL_GetCurSel (HWND hwnd, WPARAM wParam, LPARAM lParam)
831{
832 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
833 SYSTEMTIME *lpSel=(SYSTEMTIME *) lParam;
834
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;
838
839 MONTHCAL_CopyTime (&infoPtr->minSel,lpSel);
840 return TRUE;
841}
842
843
844/* FIXME: if the specified date is not visible, make it visible */
845/* FIXME: redraw? */
846
847static LRESULT
848MONTHCAL_SetCurSel (HWND hwnd, WPARAM wParam, LPARAM lParam)
849{
850 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
851 SYSTEMTIME *lpSel=(SYSTEMTIME *) lParam;
852
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;
856
857 //TRACE ("%d %d\n",lpSel->wMonth,lpSel->wDay);
858
859 MONTHCAL_CopyTime (lpSel,&infoPtr->minSel);
860 MONTHCAL_CopyTime (lpSel,&infoPtr->maxSel);
861
862 return TRUE;
863}
864
865static LRESULT
866MONTHCAL_GetMaxSelCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
867{
868 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
869
870 //TRACE ("%x %lx\n",wParam,lParam);
871 return infoPtr->maxSelCount;
872}
873
874static LRESULT
875MONTHCAL_SetMaxSelCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
876{
877 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
878
879 //TRACE ("%x %lx\n",wParam,lParam);
880 if ( GetWindowLongA( hwnd, GWL_STYLE) & MCS_MULTISELECT) {
881 infoPtr->maxSelCount=wParam;
882 }
883
884 return TRUE;
885}
886
887
888static LRESULT
889MONTHCAL_GetSelRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
890{
891 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
892 SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *) lParam;
893
894 //TRACE ("%x %lx\n",wParam,lParam);
895
896 /* validate parameters */
897
898 if ( (infoPtr==NULL) || (lprgSysTimeArray==NULL) ) return FALSE;
899
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;
905 }
906
907 return FALSE;
908}
909
910static LRESULT
911MONTHCAL_SetSelRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
912{
913 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
914 SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *) lParam;
915
916 //TRACE ("%x %lx\n",wParam,lParam);
917
918 /* validate parameters */
919
920 if ( (infoPtr==NULL) || (lprgSysTimeArray==NULL) ) return FALSE;
921
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;
927 }
928
929 return FALSE;
930}
931
932
933
934
935static LRESULT
936MONTHCAL_GetToday (HWND hwnd, WPARAM wParam, LPARAM lParam)
937{
938 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
939 SYSTEMTIME *lpToday=(SYSTEMTIME *) lParam;
940
941 //TRACE ("%x %lx\n",wParam,lParam);
942
943 /* validate parameters */
944
945 if ( (infoPtr==NULL) || (lpToday==NULL) ) return FALSE;
946 MONTHCAL_CopyTime (&infoPtr->todaysDate,lpToday);
947 return TRUE;
948}
949
950
951static LRESULT
952MONTHCAL_SetToday (HWND hwnd, WPARAM wParam, LPARAM lParam)
953{
954 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
955 SYSTEMTIME *lpToday=(SYSTEMTIME *) lParam;
956
957 //TRACE ("%x %lx\n",wParam,lParam);
958
959 /* validate parameters */
960
961 if ( (infoPtr==NULL) || (lpToday==NULL) ) return FALSE;
962 MONTHCAL_CopyTime (lpToday, &infoPtr->todaysDate);
963 return TRUE;
964}
965
966
967
968
969static LRESULT
970MONTHCAL_HitTest (HWND hwnd, LPARAM lParam)
971{
972 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
973 PMCHITTESTINFO lpht=(PMCHITTESTINFO) lParam;
974 UINT x,y;
975 DWORD retval;
976
977 x=lpht->pt.x;
978 y=lpht->pt.y;
979 retval=MCHT_NOWHERE;
980
981
982 /* are we in the header? */
983
984 if (PtInRect (&infoPtr->title, lpht->pt)) {
985
986 if (PtInRect (&infoPtr->titlebtnprev, lpht->pt)) {
987 retval=MCHT_TITLEBTNPREV;
988 goto done;
989 }
990 if (PtInRect (&infoPtr->titlebtnnext, lpht->pt)) {
991 retval=MCHT_TITLEBTNNEXT;
992 goto done;
993 }
994 if (PtInRect (&infoPtr->titlemonth, lpht->pt)) {
995 retval=MCHT_TITLEMONTH;
996 goto done;
997 }
998 if (PtInRect (&infoPtr->titleyear, lpht->pt)) {
999 retval=MCHT_TITLEYEAR;
1000 goto done;
1001 }
1002 retval=MCHT_TITLE;
1003 goto done;
1004 }
1005
1006 if (PtInRect (&infoPtr->days, lpht->pt)) {
1007 retval=MCHT_CALENDARDAY; /* FIXME: find out which day we're on */
1008 goto done;
1009 }
1010 if (PtInRect (&infoPtr->weeknums, lpht->pt)) {
1011 retval=MCHT_CALENDARWEEKNUM;/* FIXME: find out which day we're on */
1012 goto done;
1013 }
1014 if (PtInRect (&infoPtr->prevmonth, lpht->pt)) {
1015 retval=MCHT_CALENDARDATEPREV;
1016 goto done;
1017 }
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;
1023 }
1024
1025
1026 if (PtInRect (&infoPtr->today, lpht->pt)) {
1027 retval=MCHT_TODAYLINK;
1028 goto done;
1029 }
1030
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.
1035 */
1036
1037
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);
1043
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;
1048
1049 lpht->st.wDay=MONTHCAL_CalcDayFromPos (infoPtr,x,y);
1050
1051 //TRACE ("day hit: %d\n",lpht->st.wDay);
1052 retval=MCHT_CALENDARDATE;
1053 goto done;
1054
1055 }
1056
1057 /* Hit nothing special? What's left must be background :-) */
1058
1059 retval=MCHT_CALENDARBK;
1060 done:
1061 lpht->uHit=retval;
1062 return retval;
1063}
1064
1065
1066
1067static void MONTHCAL_GoToNextMonth (HWND hwnd, MONTHCAL_INFO *infoPtr)
1068{
1069 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1070
1071 //TRACE ("\n");
1072
1073 infoPtr->currentMonth++;
1074 if (infoPtr->currentMonth>12) {
1075 infoPtr->currentYear++;
1076 infoPtr->currentMonth=1;
1077 }
1078
1079 if (dwStyle & MCS_DAYSTATE) {
1080 NMDAYSTATE nmds;
1081 int i;
1082
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));
1089
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];
1094 }
1095
1096}
1097
1098
1099static void MONTHCAL_GoToPrevMonth (HWND hwnd, MONTHCAL_INFO *infoPtr)
1100{
1101 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1102
1103 //TRACE ("\n");
1104
1105 infoPtr->currentMonth--;
1106 if (infoPtr->currentMonth<1) {
1107 infoPtr->currentYear--;
1108 infoPtr->currentMonth=12;
1109 }
1110
1111 if (dwStyle & MCS_DAYSTATE) {
1112 NMDAYSTATE nmds;
1113 int i;
1114
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));
1121
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];
1126 }
1127}
1128
1129
1130static LRESULT
1131MONTHCAL_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1132
1133{
1134 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr (hwnd);
1135 MCHITTESTINFO ht;
1136 HDC hdc;
1137 DWORD hit;
1138 HMENU hMenu;
1139 HWND retval;
1140
1141
1142 //TRACE ("%x %lx\n",wParam,lParam);
1143
1144 ht.pt.x = (INT)LOWORD(lParam);
1145 ht.pt.y = (INT)HIWORD(lParam);
1146 hit=MONTHCAL_HitTest (hwnd, (LPARAM) &ht);
1147
1148 hdc=GetDC (hwnd);
1149
1150 if (hit & MCHT_NEXT){
1151 MONTHCAL_GoToNextMonth (hwnd, infoPtr);
1152 infoPtr->status=MC_NEXTPRESSED;
1153 SetTimer (hwnd, MC_NEXTMONTHTIMER, MC_NEXTMONTHDELAY,0);
1154 }
1155 if (hit & MCHT_PREV) {
1156 MONTHCAL_GoToPrevMonth (hwnd, infoPtr);
1157 infoPtr->status=MC_PREVPRESSED;
1158 SetTimer (hwnd, MC_PREVMONTHTIMER, MC_NEXTMONTHDELAY,0);
1159 }
1160
1161 if (hit == MCHT_TITLEMONTH) {
1162/*
1163 HRSRC hrsrc = FindResourceA( COMCTL32_hModule, MAKEINTRESOURCEA(IDD_MCMONTHMENU), RT_MENUA );
1164 if (!hrsrc) {
1165 TRACE ("returning zero\n");
1166 return 0;
1167 }
1168 TRACE ("resource is:%x\n",hrsrc);
1169 hMenu=LoadMenuIndirectA( (LPCVOID)LoadResource( COMCTL32_hModule, hrsrc ));
1170
1171 TRACE ("menu is:%x\n",hMenu);
1172*/
1173
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");
1178
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);
1184
1185 }
1186 if (hit == MCHT_TITLEYEAR) {
1187 //FIXME ("create updown for yearselection\n");
1188 }
1189 if (hit == MCHT_TODAYLINK) {
1190 //FIXME ("set currentday\n");
1191 }
1192 if (hit == MCHT_CALENDARDATE) {
1193 SYSTEMTIME selArray[2];
1194 NMSELCHANGE nmsc;
1195
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);
1202
1203 SendMessageA (GetParent (hwnd), WM_NOTIFY,
1204 (WPARAM)nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
1205
1206 MONTHCAL_CopyTime (&ht.st, &selArray[0]);
1207 MONTHCAL_CopyTime (&ht.st, &selArray[1]);
1208 MONTHCAL_SetSelRange (hwnd,0,(LPARAM) &selArray);
1209
1210 infoPtr->firstSelDay=ht.st.wDay;
1211 infoPtr->curSelDay=ht.st.wDay;
1212 infoPtr->status=MC_SEL_LBUTDOWN;
1213 }
1214
1215 MONTHCAL_Refresh (hwnd,hdc);
1216 ReleaseDC (hwnd,hdc);
1217 return 0;
1218}
1219
1220static LRESULT
1221MONTHCAL_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1222
1223{
1224 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr (hwnd);
1225 NMSELCHANGE nmsc;
1226 NMHDR nmhdr;
1227 HDC hdc;
1228
1229 //TRACE ("\n");
1230
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;
1237
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));
1242
1243 SendMessageA (GetParent (hwnd), WM_NOTIFY,
1244 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1245
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);
1251
1252 SendMessageA (GetParent (hwnd), WM_NOTIFY,
1253 (WPARAM)nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
1254
1255 hdc=GetDC (hwnd);
1256 MONTHCAL_Refresh (hwnd,hdc);
1257 ReleaseDC (hwnd,hdc);
1258
1259 return 0;
1260}
1261
1262static LRESULT
1263MONTHCAL_Timer (HWND hwnd, WPARAM wParam, LPARAM lParam)
1264
1265{
1266 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr (hwnd);
1267 HDC hdc;
1268
1269 //TRACE(" %d\n",wParam);
1270 if (!infoPtr) return FALSE;
1271
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");
1282 }
1283
1284 MONTHCAL_Refresh (hwnd,hdc);
1285 ReleaseDC (hwnd,hdc);
1286 return 0;
1287}
1288
1289
1290
1291static LRESULT
1292MONTHCAL_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1293{
1294 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr (hwnd);
1295 MCHITTESTINFO ht;
1296 HDC hdc;
1297 int selday,hit;
1298 RECT r;
1299
1300 if (!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0;
1301
1302 ht.pt.x=LOWORD(lParam);
1303 ht.pt.y=HIWORD(lParam);
1304
1305 hit=MONTHCAL_HitTest (hwnd, (LPARAM) &ht);
1306
1307 /* not on the calendar date numbers? bail out */
1308 //TRACE ("hit:%x\n",hit);
1309 if ((hit & MCHT_CALENDARDATE) !=MCHT_CALENDARDATE) return 0;
1310
1311 selday=ht.st.wDay;
1312 infoPtr->curSelDay=selday;
1313 MONTHCAL_CalcPosFromDay (infoPtr,selday,ht.st.wMonth,&r);
1314
1315 if ( GetWindowLongA( hwnd, GWL_STYLE) & MCS_MULTISELECT) {
1316 SYSTEMTIME selArray[2];
1317 int i;
1318
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;
1327
1328 if (selday<infoPtr->firstSelDay) i=0;
1329 }
1330
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;
1336 }
1337
1338 if (selArray[i].wDay!=selday) {
1339
1340 //TRACE ("newRange:%d %d %d %d\n",infoPtr->firstSelDay,selArray[0].wDay,selArray[1].wDay,i);
1341
1342 selArray[i].wDay=selday;
1343
1344
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;
1350 }
1351
1352 MONTHCAL_SetSelRange (hwnd,0,(LPARAM) &selArray);
1353 }
1354 }
1355
1356done:
1357
1358 hdc=GetDC (hwnd);
1359 MONTHCAL_Refresh (hwnd, hdc);
1360 ReleaseDC (hwnd, hdc);
1361
1362 return 0;
1363}
1364
1365static LRESULT
1366MONTHCAL_Paint (HWND hwnd, WPARAM wParam)
1367{
1368 HDC hdc;
1369 PAINTSTRUCT ps;
1370
1371 hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1372 MONTHCAL_Refresh (hwnd, hdc);
1373 if(!wParam)
1374 EndPaint (hwnd, &ps);
1375 return 0;
1376}
1377
1378static LRESULT
1379MONTHCAL_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
1380{
1381 HDC hdc;
1382
1383 //TRACE ("\n");
1384
1385 hdc = GetDC (hwnd);
1386 MONTHCAL_Refresh (hwnd, hdc);
1387 ReleaseDC (hwnd, hdc);
1388 InvalidateRect (hwnd, NULL, TRUE);
1389
1390 return 0;
1391}
1392
1393
1394static LRESULT
1395MONTHCAL_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
1396{
1397 HDC hdc;
1398
1399 //TRACE ("\n");
1400
1401 hdc = GetDC (hwnd);
1402 MONTHCAL_Refresh (hwnd, hdc);
1403 ReleaseDC (hwnd, hdc);
1404
1405 return 0;
1406}
1407
1408
1409/* FIXME: check whether dateMin/dateMax need to be adjusted. */
1410
1411
1412static LRESULT
1413MONTHCAL_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1414{
1415 MONTHCAL_INFO *infoPtr;
1416 LOGFONTA logFont;
1417
1418 /* allocate memory for info structure */
1419 infoPtr = (MONTHCAL_INFO *)COMCTL32_Alloc (sizeof(MONTHCAL_INFO));
1420 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
1421
1422 if (infoPtr == NULL) {
1423 //ERR ( "could not allocate info memory!\n");
1424 return 0;
1425 }
1426 if ((MONTHCAL_INFO*) GetWindowLongA( hwnd, 0) != infoPtr) {
1427 //ERR ( "pointer assignment error!\n");
1428 return 0;
1429 }
1430
1431
1432 infoPtr->hFont=GetStockObject(DEFAULT_GUI_FONT);
1433 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont);
1434 logFont.lfWeight=FW_BOLD;
1435 infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
1436
1437 /* initialize info structure */
1438 /* FIXME: calculate systemtime ->> localtime (substract timezoneinfo) */
1439
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);
1456
1457 return 0;
1458}
1459
1460
1461static LRESULT
1462MONTHCAL_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1463{
1464 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr (hwnd);
1465
1466 /* free month calendar info data */
1467 COMCTL32_Free (infoPtr);
1468
1469 return 0;
1470}
1471
1472
1473
1474static LRESULT WINAPI
1475MONTHCAL_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1476{
1477
1478 switch (uMsg)
1479 {
1480
1481 case MCM_GETCURSEL:
1482 return MONTHCAL_GetCurSel (hwnd, wParam, lParam);
1483
1484 case MCM_SETCURSEL:
1485 return MONTHCAL_SetCurSel (hwnd, wParam, lParam);
1486
1487 case MCM_GETMAXSELCOUNT:
1488 return MONTHCAL_GetMaxSelCount (hwnd, wParam, lParam);
1489
1490 case MCM_SETMAXSELCOUNT:
1491 return MONTHCAL_SetMaxSelCount (hwnd, wParam, lParam);
1492
1493 case MCM_GETSELRANGE:
1494 return MONTHCAL_GetSelRange (hwnd, wParam, lParam);
1495
1496 case MCM_SETSELRANGE:
1497 return MONTHCAL_SetSelRange (hwnd, wParam, lParam);
1498
1499 case MCM_GETMONTHRANGE:
1500 return MONTHCAL_GetMonthRange (hwnd, wParam, lParam);
1501
1502 case MCM_SETDAYSTATE:
1503 return MONTHCAL_SetDayState (hwnd, wParam, lParam);
1504
1505 case MCM_GETMINREQRECT:
1506 return MONTHCAL_GetMinReqRect (hwnd, wParam, lParam);
1507
1508 case MCM_GETCOLOR:
1509 return MONTHCAL_GetColor (hwnd, wParam, lParam);
1510
1511 case MCM_SETCOLOR:
1512 return MONTHCAL_SetColor (hwnd, wParam, lParam);
1513
1514 case MCM_GETTODAY:
1515 return MONTHCAL_GetToday (hwnd, wParam, lParam);
1516
1517 case MCM_SETTODAY:
1518 return MONTHCAL_SetToday (hwnd, wParam, lParam);
1519
1520 case MCM_HITTEST:
1521 return MONTHCAL_HitTest (hwnd,lParam);
1522
1523 case MCM_GETFIRSTDAYOFWEEK:
1524 return MONTHCAL_GetFirstDayOfWeek (hwnd, wParam, lParam);
1525
1526 case MCM_SETFIRSTDAYOFWEEK:
1527 return MONTHCAL_SetFirstDayOfWeek (hwnd, wParam, lParam);
1528
1529 case MCM_GETRANGE:
1530 return MONTHCAL_GetRange (hwnd, wParam, lParam);
1531
1532 case MCM_SETRANGE:
1533 return MONTHCAL_SetRange (hwnd, wParam, lParam);
1534
1535 case MCM_GETMONTHDELTA:
1536 return MONTHCAL_GetMonthDelta (hwnd, wParam, lParam);
1537
1538 case MCM_SETMONTHDELTA:
1539 return MONTHCAL_SetMonthDelta (hwnd, wParam, lParam);
1540
1541 case MCM_GETMAXTODAYWIDTH:
1542 return MONTHCAL_GetMaxTodayWidth (hwnd);
1543
1544 case WM_GETDLGCODE:
1545 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1546
1547 case WM_KILLFOCUS:
1548 return MONTHCAL_KillFocus (hwnd, wParam, lParam);
1549
1550 case WM_LBUTTONDOWN:
1551 return MONTHCAL_LButtonDown (hwnd, wParam, lParam);
1552
1553 case WM_MOUSEMOVE:
1554 return MONTHCAL_MouseMove (hwnd, wParam, lParam);
1555
1556 case WM_LBUTTONUP:
1557 return MONTHCAL_LButtonUp (hwnd, wParam, lParam);
1558
1559 case WM_PAINT:
1560 return MONTHCAL_Paint (hwnd, wParam);
1561
1562 case WM_SETFOCUS:
1563 return MONTHCAL_SetFocus (hwnd, wParam, lParam);
1564
1565 case WM_CREATE:
1566 return MONTHCAL_Create (hwnd, wParam, lParam);
1567
1568 case WM_TIMER:
1569 return MONTHCAL_Timer (hwnd, wParam, lParam);
1570
1571 case WM_DESTROY:
1572 return MONTHCAL_Destroy (hwnd, wParam, lParam);
1573
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);
1579 }
1580 return 0;
1581}
1582
1583
1584void
1585MONTHCAL_Register (void)
1586{
1587 WNDCLASSA wndClass;
1588
1589 if (GlobalFindAtomA (MONTHCAL_CLASSA)) return;
1590
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;
1599
1600 RegisterClassA (&wndClass);
1601}
1602
1603
1604void
1605MONTHCAL_Unregister (void)
1606{
1607 if (GlobalFindAtomA (MONTHCAL_CLASSA))
1608 UnregisterClassA (MONTHCAL_CLASSA, (HINSTANCE)NULL);
1609}
1610
Note: See TracBrowser for help on using the repository browser.