source: trunk/src/comctl32/monthcal.cpp@ 3844

Last change on this file since 3844 was 3844, checked in by bird, 25 years ago

Corrected $Id keyword.

File size: 47.7 KB
Line 
1/* $Id: monthcal.cpp,v 1.4 2000-07-18 16:17:29 bird Exp $ */
2/* Month calendar control
3 *
4 * Copyright 1998, 1999 Eric Kohl (ekohl@abo.rhein-zeitung.de)
5 * Copyright 1999 Alex Priem (alexp@sci.kun.nl)
6 * Copyright 1999 Chris Morgan <cmorgan@wpi.edu> and
7 * James Abbatiello <abbeyj@wpi.edu>
8 * Copyright 2000 Christoph Bratschi
9 *
10 * TODO:
11 * - Notifications.
12 *
13 *
14 * FIXME: refresh should ask for rect of required length. (?)
15 * FIXME: handle resources better (doesn't work now); also take care
16 of internationalization.
17 * FIXME: keyboard handling.
18 */
19
20/* Corel WINE 20000513 level */
21
22#include "winbase.h"
23#include "win.h"
24#include "commctrl.h"
25#include "comctl32.h"
26#include "ccbase.h"
27#include "monthcal.h"
28#include "winnls.h"
29#include <stdio.h>
30#include <string.h>
31#include <stdlib.h>
32
33//DEFAULT_DEBUG_CHANNEL(monthcal)
34
35/* take #days/month from ole/parsedt.c;
36 * we want full month-names, and abbreviated weekdays, so these are
37 * defined here */
38
39static const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
40
41const char * const monthtxt[] = {"January", "February", "March", "April", "May",
42 "June", "July", "August", "September", "October",
43 "November", "December"};
44const char * const daytxt[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
45static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
46
47
48#define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)getInfoPtr(hwnd))
49
50/* helper functions */
51
52/* returns the number of days in any given month */
53/* january is 1, december is 12 */
54static int MONTHCAL_MonthLength(int month, int year)
55{
56 /* if we have a leap year add 1 day to February */
57 /* a leap year is a year either divisible by 400 */
58 /* or divisible by 4 and not by 100 */
59 if(month == 2) { /* February */
60 return mdays[month - 1] + ((year%400 == 0) ? 1 : ((year%100 != 0) &&
61 (year%4 == 0)) ? 1 : 0);
62 }
63 else {
64 return mdays[month - 1];
65 }
66}
67
68
69/* make sure that time is valid */
70static int MONTHCAL_ValidateTime(SYSTEMTIME time)
71{
72 if(time.wMonth > 12) return FALSE;
73 if(time.wDayOfWeek > 6) return FALSE;
74 if(time.wDay > MONTHCAL_MonthLength(time.wMonth, time.wYear))
75 return FALSE;
76 if(time.wHour > 23) return FALSE;
77 if(time.wMinute > 59) return FALSE;
78 if(time.wSecond > 59) return FALSE;
79 if(time.wMilliseconds > 999) return FALSE;
80
81 return TRUE;
82}
83
84
85void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to)
86{
87 to->wYear = from->wYear;
88 to->wMonth = from->wMonth;
89 to->wDayOfWeek = from->wDayOfWeek;
90 to->wDay = from->wDay;
91 to->wHour = from->wHour;
92 to->wMinute = from->wMinute;
93 to->wSecond = from->wSecond;
94 to->wMilliseconds = from->wMilliseconds;
95}
96
97
98/* Note:Depending on DST, this may be offset by a day.
99 Need to find out if we're on a DST place & adjust the clock accordingly.
100 Above function assumes we have a valid data.
101 Valid for year>1752; 1 <= d <= 31, 1 <= m <= 12.
102 0 = Monday.
103*/
104
105/* returns the day in the week(0 == sunday, 6 == saturday) */
106/* day(1 == 1st, 2 == 2nd... etc), year is the year value */
107int MONTHCAL_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year)
108{
109 year-=(month < 3);
110
111 return((year + year/4 - year/100 + year/400 +
112 DayOfWeekTable[month-1] + day - 1 ) % 7);
113}
114
115
116static int MONTHCAL_CalcDayFromPos(MONTHCAL_INFO *infoPtr, int x, int y)
117{
118 int daypos, weekpos, retval, firstDay;
119
120 /* if the point is outside the x bounds of the window put
121 it at the boundry */
122 if(x > (infoPtr->width_increment * 7.0)) {
123 x = infoPtr->rcClient.right - infoPtr->rcClient.left - infoPtr->left_offset;
124 }
125
126 daypos = (x -(infoPtr->prevmonth.left + infoPtr->left_offset)) / infoPtr->width_increment;
127 weekpos = (y - infoPtr->days.bottom - infoPtr->rcClient.top) / infoPtr->height_increment;
128
129 firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear);
130 retval = daypos + (7 * weekpos) - firstDay;
131 //TRACE("%d %d %d\n", daypos, weekpos, retval);
132 return retval;
133}
134
135/* day is the day of the month, 1 == 1st day of the month */
136/* sets x and y to be the position of the day */
137/* x == day, y == week where(0,0) == sunday, 1st week */
138static void MONTHCAL_CalcDayXY(MONTHCAL_INFO *infoPtr, int day, int month,
139 int *x, int *y)
140{
141 int firstDay, prevMonth;
142
143 firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear);
144
145 if(month==infoPtr->currentMonth) {
146 *x = (day + firstDay) % 7;
147 *y = (day + firstDay - *x) / 7;
148 return;
149 }
150 if(month < infoPtr->currentMonth) {
151 prevMonth = month - 1;
152 if(prevMonth==0)
153 prevMonth = 12;
154
155 *x = (MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) - firstDay) % 7;
156 *y = 0;
157 return;
158 }
159
160 *y = MONTHCAL_MonthLength(month, infoPtr->currentYear - 1) / 7;
161 *x = (day + firstDay + MONTHCAL_MonthLength(month,
162 infoPtr->currentYear)) % 7;
163}
164
165
166/* x: column(day), y: row(week) */
167static void MONTHCAL_CalcDayRect(MONTHCAL_INFO *infoPtr, RECT *r, int x, int y)
168{
169 r->left = infoPtr->prevmonth.left + x * infoPtr->width_increment + infoPtr->left_offset;
170 r->right = r->left + infoPtr->width_increment;
171 r->top = infoPtr->height_increment * y + infoPtr->days.bottom + infoPtr->top_offset;
172 r->bottom = r->top + infoPtr->textHeight;
173}
174
175
176/* sets the RECT struct r to the rectangle around the day and month */
177/* day is the day value of the month(1 == 1st), month is the month */
178/* value(january == 1, december == 12) */
179static void MONTHCAL_CalcPosFromDay(MONTHCAL_INFO *infoPtr,
180 int day, int month, RECT *r)
181{
182 int x, y;
183
184 MONTHCAL_CalcDayXY(infoPtr, day, month, &x, &y);
185 MONTHCAL_CalcDayRect(infoPtr, r, x, y);
186}
187
188
189/* day is the day in the month(1 == 1st of the month) */
190/* month is the month value(1 == january, 12 == december) */
191static void MONTHCAL_CircleDay(HDC hdc, MONTHCAL_INFO *infoPtr, int day,
192int month)
193{
194 HPEN hRedPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
195 HPEN hOldPen2 = SelectObject(hdc, hRedPen);
196 POINT points[13];
197 int x, y;
198 RECT day_rect;
199
200 /* use prevmonth to calculate position because it contains the extra width
201 * from MCS_WEEKNUMBERS
202 */
203
204 MONTHCAL_CalcPosFromDay(infoPtr, day, month, &day_rect);
205
206 x = day_rect.left;
207 y = day_rect.top;
208
209 points[0].x = x;
210 points[0].y = y - 1;
211 points[1].x = x + 0.8 * infoPtr->width_increment;
212 points[1].y = y - 1;
213 points[2].x = x + 0.9 * infoPtr->width_increment;
214 points[2].y = y;
215 points[3].x = x + infoPtr->width_increment;
216 points[3].y = y + 0.5 * infoPtr->textHeight;
217
218 points[4].x = x + infoPtr->width_increment;
219 points[4].y = y + 0.9 * infoPtr->textHeight;
220 points[5].x = x + 0.6 * infoPtr->width_increment;
221 points[5].y = y + 0.9 * infoPtr->textHeight;
222 points[6].x = x + 0.5 * infoPtr->width_increment;
223 points[6].y = y + 0.9 * infoPtr->textHeight; /* bring the bottom up just
224 a hair to fit inside the day rectangle */
225
226 points[7].x = x + 0.2 * infoPtr->width_increment;
227 points[7].y = y + 0.8 * infoPtr->textHeight;
228 points[8].x = x + 0.1 * infoPtr->width_increment;
229 points[8].y = y + 0.8 * infoPtr->textHeight;
230 points[9].x = x;
231 points[9].y = y + 0.5 * infoPtr->textHeight;
232
233 points[10].x = x + 0.1 * infoPtr->width_increment;
234 points[10].y = y + 0.2 * infoPtr->textHeight;
235 points[11].x = x + 0.2 * infoPtr->width_increment;
236 points[11].y = y + 0.3 * infoPtr->textHeight;
237 points[12].x = x + 0.5 * infoPtr->width_increment;
238 points[12].y = y + 0.3 * infoPtr->textHeight;
239
240 PolyBezier(hdc, points, 13);
241 DeleteObject(hRedPen);
242 SelectObject(hdc, hOldPen2);
243}
244
245
246static void MONTHCAL_DrawDay(HDC hdc, MONTHCAL_INFO *infoPtr,
247 int day, int month, int x, int y, int bold)
248{
249 char buf[10];
250 RECT r;
251 static int haveBoldFont, haveSelectedDay = FALSE;
252 HBRUSH hbr;
253 HPEN hNewPen, hOldPen = 0;
254 COLORREF oldCol = 0;
255 COLORREF oldBk = 0;
256
257 sprintf(buf, "%d", day);
258
259/* No need to check styles: when selection is not valid, it is set to zero.
260 * 1<day<31, so evertyhing's OK.
261 */
262
263 MONTHCAL_CalcDayRect(infoPtr, &r, x, y);
264
265 if((day>=infoPtr->minSel.wDay) && (day<=infoPtr->maxSel.wDay)
266 && (month==infoPtr->currentMonth)) {
267 HRGN hrgn;
268 RECT r2;
269
270 //TRACE("%d %d %d\n",day, infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
271 //TRACE("%d %d %d %d\n", r.left, r.top, r.right, r.bottom);
272 oldCol = SetTextColor(hdc, infoPtr->monthbk);
273 oldBk = SetBkColor(hdc, infoPtr->trailingtxt);
274 hbr = GetSysColorBrush(COLOR_GRAYTEXT);
275 hrgn = CreateEllipticRgn(r.left, r.top, r.right, r.bottom);
276 FillRgn(hdc, hrgn, hbr);
277
278 /* FIXME: this may need to be changed now b/c of the other
279 drawing changes 11/3/99 CMM */
280 r2.left = r.left - 0.25 * infoPtr->textWidth;
281 r2.top = r.top;
282 r2.right = r.left + 0.5 * infoPtr->textWidth;
283 r2.bottom = r.bottom;
284 if(haveSelectedDay) FillRect(hdc, &r2, hbr);
285 haveSelectedDay = TRUE;
286 } else {
287 haveSelectedDay = FALSE;
288 }
289
290 /* need to add some code for multiple selections */
291
292 if((bold) &&(!haveBoldFont)) {
293 SelectObject(hdc, infoPtr->hBoldFont);
294 haveBoldFont = TRUE;
295 }
296 if((!bold) &&(haveBoldFont)) {
297 SelectObject(hdc, infoPtr->hFont);
298 haveBoldFont = FALSE;
299 }
300
301 if(haveSelectedDay) {
302 SetTextColor(hdc, oldCol);
303 SetBkColor(hdc, oldBk);
304 }
305
306 DrawTextA(hdc, buf, lstrlenA(buf), &r,
307 DT_CENTER | DT_VCENTER | DT_SINGLELINE );
308
309 /* draw a rectangle around the currently selected days text */
310 if((day==infoPtr->curSelDay) && (month==infoPtr->currentMonth)) {
311 hNewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) );
312 hbr = GetSysColorBrush(COLOR_WINDOWTEXT);
313 FrameRect(hdc, &r, hbr);
314 SelectObject(hdc, hOldPen);
315 }
316}
317
318
319/* CHECKME: For `todays date', do we need to check the locale?*/
320static void MONTHCAL_Refresh(HWND hwnd, HDC hdc)
321{
322 MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
323 RECT *rcClient=&infoPtr->rcClient;
324 RECT *rcDraw=&infoPtr->rcDraw;
325 RECT *title=&infoPtr->title;
326 RECT *prev=&infoPtr->titlebtnprev;
327 RECT *next=&infoPtr->titlebtnnext;
328 RECT *titlemonth=&infoPtr->titlemonth;
329 RECT *titleyear=&infoPtr->titleyear;
330 RECT *prevmonth=&infoPtr->prevmonth;
331 RECT *nextmonth=&infoPtr->nextmonth;
332 RECT dayrect;
333 RECT *days=&dayrect;
334 RECT *weeknums=&infoPtr->weeknums;
335 RECT *rtoday=&infoPtr->today;
336 int i, j, m, mask, day, firstDay, weeknum, prevMonth;
337 int textHeight = infoPtr->textHeight, textWidth = infoPtr->textWidth;
338 SIZE size;
339 HBRUSH hbr;
340 HFONT currentFont;
341 /* LOGFONTA logFont; */
342 char buf[20];
343 const char *thisMonthtxt;
344 COLORREF oldTextColor, oldBkColor;
345 DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
346 BOOL prssed;
347
348 oldTextColor = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
349
350 /* draw control edge */
351 hbr = CreateSolidBrush(RGB(255, 255, 255));
352 FillRect(hdc, rcClient, hbr);
353 DrawEdge(hdc, rcClient, EDGE_SUNKEN, BF_RECT);
354 DeleteObject(hbr);
355 prssed = FALSE;
356
357 /* draw header */
358 hbr = CreateSolidBrush(infoPtr->titlebk);
359 FillRect(hdc, title, hbr);
360
361 /* if the previous button is pressed draw it depressed */
362 if((infoPtr->status & MC_PREVPRESSED))
363 DrawFrameControl(hdc, prev, DFC_SCROLL,
364 DFCS_SCROLLLEFT | DFCS_PUSHED |
365 (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0));
366 else /* if the previous button is pressed draw it depressed */
367 DrawFrameControl(hdc, prev, DFC_SCROLL,
368 DFCS_SCROLLLEFT |(dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0));
369
370 /* if next button is depressed draw it depressed */
371 if((infoPtr->status & MC_NEXTPRESSED))
372 DrawFrameControl(hdc, next, DFC_SCROLL,
373 DFCS_SCROLLRIGHT | DFCS_PUSHED |
374 (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0));
375 else /* if the next button is pressed draw it depressed */
376 DrawFrameControl(hdc, next, DFC_SCROLL,
377 DFCS_SCROLLRIGHT |(dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0));
378
379 oldBkColor = SetBkColor(hdc, infoPtr->titlebk);
380 SetTextColor(hdc, infoPtr->titletxt);
381 currentFont = SelectObject(hdc, infoPtr->hBoldFont);
382
383 /* titlemonth->left and right are set in MONTHCAL_UpdateSize */
384 titlemonth->left = title->left;
385 titlemonth->right = title->right;
386
387 thisMonthtxt = monthtxt[infoPtr->currentMonth - 1];
388 sprintf(buf, "%s %ld", thisMonthtxt, infoPtr->currentYear);
389 DrawTextA(hdc, buf, strlen(buf), titlemonth,
390 DT_CENTER | DT_VCENTER | DT_SINGLELINE);
391 SelectObject(hdc, infoPtr->hFont);
392
393/* titlemonth left/right contained rect for whole titletxt('June 1999')
394 * MCM_HitTestInfo wants month & year rects, so prepare these now.
395 *(no, we can't draw them separately; the whole text is centered)
396 */
397 GetTextExtentPoint32A(hdc, buf, lstrlenA(buf), &size);
398 titlemonth->left = title->right / 2 - size.cx / 2;
399 titleyear->right = title->right / 2 + size.cx / 2;
400 GetTextExtentPoint32A(hdc, thisMonthtxt, lstrlenA(thisMonthtxt), &size);
401 titlemonth->right = titlemonth->left + size.cx;
402 titleyear->right = titlemonth->right;
403
404
405/* draw line under day abbreviatons */
406
407 if(dwStyle & MCS_WEEKNUMBERS)
408 MoveToEx(hdc, rcDraw->left + textWidth + 3, title->bottom + textHeight + 2, NULL);
409 else
410 MoveToEx(hdc, rcDraw->left + 3, title->bottom + textHeight + 2, NULL);
411
412 LineTo(hdc, rcDraw->right - 3, title->bottom + textHeight + 2);
413
414/* draw day abbreviations */
415
416 SetBkColor(hdc, infoPtr->monthbk);
417 SetTextColor(hdc, infoPtr->trailingtxt);
418
419 /* copy this rect so we can change the values without changing */
420 /* the original version */
421 days->left = infoPtr->days.left;
422 days->right = infoPtr->days.right;
423 days->top = infoPtr->days.top;
424 days->bottom = infoPtr->days.bottom;
425
426 i = infoPtr->firstDay;
427
428 for(j=0; j<7; j++) {
429 DrawTextA(hdc, daytxt[i], strlen(daytxt[i]), days,
430 DT_CENTER | DT_VCENTER | DT_SINGLELINE );
431 i = (i + 1) % 7;
432 days->left+=infoPtr->width_increment;
433 days->right+=infoPtr->width_increment;
434 }
435
436 days->left = rcDraw->left + j;
437 if(dwStyle & MCS_WEEKNUMBERS) days->left+=textWidth;
438 /* FIXME: this may need to be changed now 11/10/99 CMM */
439 days->right = rcDraw->left + (j+1) * textWidth - 2;
440
441/* draw day numbers; first, the previous month */
442
443 firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear);
444
445 prevMonth = infoPtr->currentMonth - 1;
446 if(prevMonth == 0) /* if currentMonth is january(1) prevMonth is */
447 prevMonth = 12; /* december(12) of the previous year */
448
449 day = MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) - firstDay;
450 mask = 1<<(day-1);
451
452 i = 0;
453 m = 0;
454 while(day <= MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)) {
455 MONTHCAL_DrawDay(hdc, infoPtr, day, prevMonth, i, 0,
456 infoPtr->monthdayState[m] & mask);
457 mask<<=1;
458 day++;
459 i++;
460 }
461
462 prevmonth->left = 0;
463 if(dwStyle & MCS_WEEKNUMBERS) prevmonth->left = textWidth;
464 prevmonth->right = prevmonth->left + i * textWidth;
465 prevmonth->top = days->bottom;
466 prevmonth->bottom = prevmonth->top + textHeight;
467
468/* draw `current' month */
469
470 day = 1; /* start at the beginning of the current month */
471
472 infoPtr->firstDayplace = i;
473 SetTextColor(hdc, infoPtr->txt);
474 m++;
475 mask = 1;
476
477 /* draw the first week of the current month */
478 while(i<7) {
479 MONTHCAL_DrawDay(hdc, infoPtr, day, infoPtr->currentMonth, i, 0,
480 infoPtr->monthdayState[m] & mask);
481
482 if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) &&
483 (day==infoPtr->todaysDate.wDay) &&
484 (infoPtr->currentYear == infoPtr->todaysDate.wYear)) {
485 MONTHCAL_CircleDay(hdc, infoPtr, day, infoPtr->currentMonth);
486 }
487
488 mask<<=1;
489 day++;
490 i++;
491 }
492
493 j = 1; /* move to the 2nd week of the current month */
494 i = 0; /* move back to sunday */
495 while(day <= MONTHCAL_MonthLength(infoPtr->currentMonth, infoPtr->currentYear)) {
496 MONTHCAL_DrawDay(hdc, infoPtr, day, infoPtr->currentMonth, i, j,
497 infoPtr->monthdayState[m] & mask);
498
499 if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) &&
500 (day==infoPtr->todaysDate.wDay) &&
501 (infoPtr->currentYear == infoPtr->todaysDate.wYear))
502 MONTHCAL_CircleDay(hdc, infoPtr, day, infoPtr->currentMonth);
503
504 mask<<=1;
505 day++;
506 i++;
507 if(i>6) { /* past saturday, goto the next weeks sunday */
508 i = 0;
509 j++;
510 }
511 }
512
513/* draw `next' month */
514
515/* note: the nextmonth rect only hints for the `half-week' that needs to be
516 * drawn to complete the current week. An eventual next week that needs to
517 * be drawn to complete the month calendar is not taken into account in
518 * this rect -- HitTest knows about this.*/
519
520 nextmonth->left = prevmonth->left + i * textWidth;
521 nextmonth->right = rcDraw->right;
522 nextmonth->top = days->bottom + (j+1) * textHeight;
523 nextmonth->bottom = nextmonth->top + textHeight;
524
525 day = 1; /* start at the first day of the next month */
526 m++;
527 mask = 1;
528
529 SetTextColor(hdc, infoPtr->trailingtxt);
530 while((i<7) &&(j<6)) {
531 MONTHCAL_DrawDay(hdc, infoPtr, day, infoPtr->currentMonth + 1, i, j,
532 infoPtr->monthdayState[m] & mask);
533
534 mask<<=1;
535 day++;
536 i++;
537 if(i==7) { /* past saturday, go to next week's sunday */
538 i = 0;
539 j++;
540 }
541 }
542 SetTextColor(hdc, infoPtr->txt);
543
544
545/* draw `today' date if style allows it, and draw a circle before today's
546 * date if necessary */
547
548 if(!(dwStyle & MCS_NOTODAY)) {
549 int offset = 0;
550 if(!(dwStyle & MCS_NOTODAYCIRCLE)) {
551 MONTHCAL_CircleDay(hdc, infoPtr, day, infoPtr->currentMonth + 1);
552 offset+=textWidth;
553 }
554 MONTHCAL_CalcDayRect(infoPtr, rtoday, offset==textWidth, 6);
555 sprintf(buf, "Today: %d/%d/%d", infoPtr->todaysDate.wMonth,
556 infoPtr->todaysDate.wDay, infoPtr->todaysDate.wYear % 100);
557 rtoday->right = rcDraw->right;
558 SelectObject(hdc, infoPtr->hBoldFont);
559 DrawTextA(hdc, buf, lstrlenA(buf), rtoday,
560 DT_LEFT | DT_VCENTER | DT_SINGLELINE);
561 SelectObject(hdc, infoPtr->hFont);
562 }
563
564 if(dwStyle & MCS_WEEKNUMBERS) {
565 /* display weeknumbers*/
566 weeknums->left = 0;
567 weeknums->right = textWidth;
568 weeknums->top = days->bottom + 2;
569 weeknums->bottom = days->bottom + 2 + textHeight;
570
571 weeknum = 0;
572 for(i=0; i<infoPtr->currentMonth-1; i++)
573 weeknum+=MONTHCAL_MonthLength(i, infoPtr->currentYear);
574
575 weeknum/=7;
576 for(i=0; i<6; i++) {
577 sprintf(buf, "%d", weeknum + i);
578 DrawTextA(hdc, buf, lstrlenA(buf), weeknums,
579 DT_CENTER | DT_BOTTOM | DT_SINGLELINE );
580 weeknums->top+=textHeight * 1.25;
581 weeknums->bottom+=textHeight * 1.25;
582 }
583
584 MoveToEx(hdc, weeknums->right, days->bottom + 5 , NULL);
585 LineTo(hdc, weeknums->right, weeknums->bottom - 1.25 * textHeight - 5);
586
587 }
588
589 /* currentFont was font at entering Refresh */
590
591 SetBkColor(hdc, oldBkColor);
592 SelectObject(hdc, currentFont);
593 SetTextColor(hdc, oldTextColor);
594}
595
596
597static LRESULT
598MONTHCAL_GetMinReqRect(HWND hwnd, WPARAM wParam, LPARAM lParam)
599{
600 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
601 LPRECT lpRect = (LPRECT) lParam;
602 //TRACE("%x %lx\n", wParam, lParam);
603
604 /* validate parameters */
605
606 if((infoPtr==NULL) ||(lpRect == NULL) ) return FALSE;
607
608 lpRect->left = infoPtr->rcClient.left;
609 lpRect->right = infoPtr->rcClient.right;
610 lpRect->top = infoPtr->rcClient.top;
611 lpRect->bottom = infoPtr->rcClient.bottom;
612 return TRUE;
613}
614
615static LRESULT
616MONTHCAL_GetColor(HWND hwnd, WPARAM wParam, LPARAM lParam)
617{
618 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
619
620 //TRACE("%x %lx\n", wParam, lParam);
621
622 switch((int)wParam) {
623 case MCSC_BACKGROUND:
624 return infoPtr->bk;
625 case MCSC_TEXT:
626 return infoPtr->txt;
627 case MCSC_TITLEBK:
628 return infoPtr->titlebk;
629 case MCSC_TITLETEXT:
630 return infoPtr->titletxt;
631 case MCSC_MONTHBK:
632 return infoPtr->monthbk;
633 case MCSC_TRAILINGTEXT:
634 return infoPtr->trailingtxt;
635 }
636
637 return -1;
638}
639
640static LRESULT
641MONTHCAL_SetColor(HWND hwnd, WPARAM wParam, LPARAM lParam)
642{
643 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
644 int prev = -1;
645
646 //TRACE("%x %lx\n", wParam, lParam);
647
648 switch((int)wParam) {
649 case MCSC_BACKGROUND:
650 prev = infoPtr->bk;
651 infoPtr->bk = (COLORREF)lParam;
652 break;
653 case MCSC_TEXT:
654 prev = infoPtr->txt;
655 infoPtr->txt = (COLORREF)lParam;
656 break;
657 case MCSC_TITLEBK:
658 prev = infoPtr->titlebk;
659 infoPtr->titlebk = (COLORREF)lParam;
660 break;
661 case MCSC_TITLETEXT:
662 prev=infoPtr->titletxt;
663 infoPtr->titletxt = (COLORREF)lParam;
664 break;
665 case MCSC_MONTHBK:
666 prev = infoPtr->monthbk;
667 infoPtr->monthbk = (COLORREF)lParam;
668 break;
669 case MCSC_TRAILINGTEXT:
670 prev = infoPtr->trailingtxt;
671 infoPtr->trailingtxt = (COLORREF)lParam;
672 break;
673 }
674
675 return prev;
676}
677
678static LRESULT
679MONTHCAL_GetMonthDelta(HWND hwnd, WPARAM wParam, LPARAM lParam)
680{
681 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
682
683 //TRACE("%x %lx\n", wParam, lParam);
684
685 if(infoPtr->delta)
686 return infoPtr->delta;
687 else
688 return infoPtr->visible;
689}
690
691static LRESULT
692MONTHCAL_SetMonthDelta(HWND hwnd, WPARAM wParam, LPARAM lParam)
693{
694 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
695 int prev = infoPtr->delta;
696
697 //TRACE("%x %lx\n", wParam, lParam);
698
699 infoPtr->delta = (int)wParam;
700 return prev;
701}
702
703
704static LRESULT
705MONTHCAL_GetFirstDayOfWeek(HWND hwnd, WPARAM wParam, LPARAM lParam)
706{
707 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
708
709 return infoPtr->firstDay;
710}
711
712
713/* sets the first day of the week that will appear in the control */
714/* 0 == Monday, 6 == Sunday */
715/* FIXME: this needs to be implemented properly in MONTHCAL_Refresh() */
716/* FIXME: we need more error checking here */
717static LRESULT
718MONTHCAL_SetFirstDayOfWeek(HWND hwnd, WPARAM wParam, LPARAM lParam)
719{
720 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
721 int prev = infoPtr->firstDay;
722 char buf[40];
723 int day;
724
725 //TRACE("%x %lx\n", wParam, lParam);
726
727 if((lParam >= 0) && (lParam < 7)) {
728 infoPtr->firstDay = (int)lParam;
729 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK,
730 buf, sizeof(buf));
731 //TRACE("%s %d\n", buf, strlen(buf));
732 if((sscanf(buf, "%d", &day) == 1) &&(infoPtr->firstDay != day))
733 infoPtr->firstDay = day;
734 }
735 return prev;
736}
737
738
739/* FIXME: fill this in */
740static LRESULT
741MONTHCAL_GetMonthRange(HWND hwnd, WPARAM wParam, LPARAM lParam)
742{
743 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
744
745 //TRACE("%x %lx\n", wParam, lParam);
746 //FIXME("stub\n");
747
748 return infoPtr->monthRange;
749}
750
751
752static LRESULT
753MONTHCAL_GetMaxTodayWidth(HWND hwnd)
754{
755 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
756
757 return(infoPtr->today.right - infoPtr->today.left);
758}
759
760
761/* FIXME: are validated times taken from current date/time or simply
762 * copied?
763 * FIXME: check whether MCM_GETMONTHRANGE shows correct result after
764 * adjusting range with MCM_SETRANGE
765 */
766
767static LRESULT
768MONTHCAL_SetRange(HWND hwnd, WPARAM wParam, LPARAM lParam)
769{
770 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
771 SYSTEMTIME lprgSysTimeArray[1];
772 int prev;
773
774 //TRACE("%x %lx\n", wParam, lParam);
775
776 if(wParam & GDTR_MAX) {
777 if(MONTHCAL_ValidateTime(lprgSysTimeArray[1])){
778 MONTHCAL_CopyTime(&lprgSysTimeArray[1], &infoPtr->maxDate);
779 infoPtr->rangeValid|=GDTR_MAX;
780 } else {
781 GetSystemTime(&infoPtr->todaysDate);
782 MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate);
783 }
784 }
785 if(wParam & GDTR_MIN) {
786 if(MONTHCAL_ValidateTime(lprgSysTimeArray[0])) {
787 MONTHCAL_CopyTime(&lprgSysTimeArray[0], &infoPtr->maxDate);
788 infoPtr->rangeValid|=GDTR_MIN;
789 } else {
790 GetSystemTime(&infoPtr->todaysDate);
791 MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate);
792 }
793 }
794
795 prev = infoPtr->monthRange;
796 infoPtr->monthRange = infoPtr->maxDate.wMonth - infoPtr->minDate.wMonth;
797
798 if(infoPtr->monthRange!=prev) {
799 COMCTL32_ReAlloc(infoPtr->monthdayState,
800 infoPtr->monthRange * sizeof(MONTHDAYSTATE));
801 }
802
803 return 1;
804}
805
806
807/* CHECKME: At the moment, we copy ranges anyway,regardless of
808 * infoPtr->rangeValid; a invalid range is simply filled with zeros in
809 * SetRange. Is this the right behavior?
810*/
811
812static LRESULT
813MONTHCAL_GetRange(HWND hwnd, WPARAM wParam, LPARAM lParam)
814{
815 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
816 SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *)lParam;
817
818 /* validate parameters */
819
820 if((infoPtr==NULL) || (lprgSysTimeArray==NULL)) return FALSE;
821
822 MONTHCAL_CopyTime(&infoPtr->maxDate, &lprgSysTimeArray[1]);
823 MONTHCAL_CopyTime(&infoPtr->minDate, &lprgSysTimeArray[0]);
824
825 return infoPtr->rangeValid;
826}
827
828
829static LRESULT
830MONTHCAL_SetDayState(HWND hwnd, WPARAM wParam, LPARAM lParam)
831
832{
833 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
834 int i, iMonths = (int)wParam;
835 MONTHDAYSTATE *dayStates = (LPMONTHDAYSTATE)lParam;
836
837 //TRACE("%x %lx\n", wParam, lParam);
838 if(iMonths!=infoPtr->monthRange) return 0;
839
840 for(i=0; i<iMonths; i++)
841 infoPtr->monthdayState[i] = dayStates[i];
842 return 1;
843}
844
845
846static LRESULT
847MONTHCAL_GetCurSel(HWND hwnd, WPARAM wParam, LPARAM lParam)
848{
849 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
850 SYSTEMTIME *lpSel = (SYSTEMTIME *) lParam;
851
852 //TRACE("%x %lx\n", wParam, lParam);
853 if((infoPtr==NULL) ||(lpSel==NULL)) return FALSE;
854 if(GetWindowLongA(hwnd, GWL_STYLE) & MCS_MULTISELECT) return FALSE;
855
856 MONTHCAL_CopyTime(&infoPtr->minSel, lpSel);
857 return TRUE;
858}
859
860
861/* FIXME: if the specified date is not visible, make it visible */
862/* FIXME: redraw? */
863static LRESULT
864MONTHCAL_SetCurSel(HWND hwnd, WPARAM wParam, LPARAM lParam)
865{
866 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
867 SYSTEMTIME *lpSel = (SYSTEMTIME *)lParam;
868
869 //TRACE("%x %lx\n", wParam, lParam);
870 if((infoPtr==NULL) ||(lpSel==NULL)) return FALSE;
871 if(GetWindowLongA(hwnd, GWL_STYLE) & MCS_MULTISELECT) return FALSE;
872
873 //TRACE("%d %d\n", lpSel->wMonth, lpSel->wDay);
874
875 MONTHCAL_CopyTime(lpSel, &infoPtr->minSel);
876 MONTHCAL_CopyTime(lpSel, &infoPtr->maxSel);
877
878 return TRUE;
879}
880
881
882static LRESULT
883MONTHCAL_GetMaxSelCount(HWND hwnd, WPARAM wParam, LPARAM lParam)
884{
885 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
886
887 //TRACE("%x %lx\n", wParam, lParam);
888 return infoPtr->maxSelCount;
889}
890
891
892static LRESULT
893MONTHCAL_SetMaxSelCount(HWND hwnd, WPARAM wParam, LPARAM lParam)
894{
895 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
896
897 //TRACE("%x %lx\n", wParam, lParam);
898 if(GetWindowLongA(hwnd, GWL_STYLE) & MCS_MULTISELECT) {
899 infoPtr->maxSelCount = wParam;
900 }
901
902 return TRUE;
903}
904
905
906static LRESULT
907MONTHCAL_GetSelRange(HWND hwnd, WPARAM wParam, LPARAM lParam)
908{
909 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
910 SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *) lParam;
911
912 //TRACE("%x %lx\n", wParam, lParam);
913
914 /* validate parameters */
915
916 if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE;
917
918 if(GetWindowLongA(hwnd, GWL_STYLE) & MCS_MULTISELECT)
919 {
920 MONTHCAL_CopyTime(&infoPtr->maxSel, &lprgSysTimeArray[1]);
921 MONTHCAL_CopyTime(&infoPtr->minSel, &lprgSysTimeArray[0]);
922 //TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
923 return TRUE;
924 }
925
926 return FALSE;
927}
928
929
930static LRESULT
931MONTHCAL_SetSelRange(HWND hwnd, WPARAM wParam, LPARAM lParam)
932{
933 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
934 SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *) lParam;
935
936 //TRACE("%x %lx\n", wParam, lParam);
937
938 /* validate parameters */
939
940 if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE;
941
942 if(GetWindowLongA( hwnd, GWL_STYLE) & MCS_MULTISELECT)
943 {
944 MONTHCAL_CopyTime(&lprgSysTimeArray[1], &infoPtr->maxSel);
945 MONTHCAL_CopyTime(&lprgSysTimeArray[0], &infoPtr->minSel);
946 //TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
947 return TRUE;
948 }
949
950 return FALSE;
951}
952
953
954static LRESULT
955MONTHCAL_GetToday(HWND hwnd, WPARAM wParam, LPARAM lParam)
956{
957 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
958 SYSTEMTIME *lpToday = (SYSTEMTIME *) lParam;
959
960 //TRACE("%x %lx\n", wParam, lParam);
961
962 /* validate parameters */
963
964 if((infoPtr==NULL) || (lpToday==NULL)) return FALSE;
965 MONTHCAL_CopyTime(&infoPtr->todaysDate, lpToday);
966 return TRUE;
967}
968
969
970static LRESULT
971MONTHCAL_SetToday(HWND hwnd, WPARAM wParam, LPARAM lParam)
972{
973 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
974 SYSTEMTIME *lpToday = (SYSTEMTIME *) lParam;
975
976 //TRACE("%x %lx\n", wParam, lParam);
977
978 /* validate parameters */
979
980 if((infoPtr==NULL) ||(lpToday==NULL)) return FALSE;
981 MONTHCAL_CopyTime(lpToday, &infoPtr->todaysDate);
982 return TRUE;
983}
984
985
986static LRESULT
987MONTHCAL_HitTest(HWND hwnd, LPARAM lParam)
988{
989 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
990 PMCHITTESTINFO lpht = (PMCHITTESTINFO)lParam;
991 UINT x,y;
992 DWORD retval;
993
994 x = lpht->pt.x;
995 y = lpht->pt.y;
996 retval = MCHT_NOWHERE;
997
998
999 /* are we in the header? */
1000
1001 if(PtInRect(&infoPtr->title, lpht->pt)) {
1002 if(PtInRect(&infoPtr->titlebtnprev, lpht->pt)) {
1003 retval = MCHT_TITLEBTNPREV;
1004 goto done;
1005 }
1006 if(PtInRect(&infoPtr->titlebtnnext, lpht->pt)) {
1007 retval = MCHT_TITLEBTNNEXT;
1008 goto done;
1009 }
1010 if(PtInRect(&infoPtr->titlemonth, lpht->pt)) {
1011 retval = MCHT_TITLEMONTH;
1012 goto done;
1013 }
1014 if(PtInRect(&infoPtr->titleyear, lpht->pt)) {
1015 retval = MCHT_TITLEYEAR;
1016 goto done;
1017 }
1018
1019 retval = MCHT_TITLE;
1020 goto done;
1021 }
1022
1023 if(PtInRect(&infoPtr->days, lpht->pt)) {
1024 retval = MCHT_CALENDARDAY; /* FIXME: find out which day we're on */
1025 goto done;
1026 }
1027 if(PtInRect(&infoPtr->weeknums, lpht->pt)) {
1028 retval = MCHT_CALENDARWEEKNUM; /* FIXME: find out which day we're on */
1029 goto done;
1030 }
1031 if(PtInRect(&infoPtr->prevmonth, lpht->pt)) {
1032 retval = MCHT_CALENDARDATEPREV;
1033 goto done;
1034 }
1035
1036 if(PtInRect(&infoPtr->nextmonth, lpht->pt) ||
1037 ((x>infoPtr->nextmonth.left) &&(x<infoPtr->nextmonth.right) &&
1038 (y>infoPtr->nextmonth.bottom) &&(y<infoPtr->today.top ))) {
1039 retval = MCHT_CALENDARDATENEXT;
1040 goto done;
1041 }
1042
1043 if(PtInRect(&infoPtr->today, lpht->pt)) {
1044 retval = MCHT_TODAYLINK;
1045 goto done;
1046 }
1047
1048/* MCHT_CALENDARDATE determination: since the next & previous month have
1049 * been handled already(MCHT_CALENDARDATEPREV/NEXT), we only have to check
1050 * whether we're in the calendar area. infoPtr->prevMonth.left handles the
1051 * MCS_WEEKNUMBERS style nicely.
1052 */
1053
1054
1055 //TRACE("%d %d [%d %d %d %d] [%d %d %d %d]\n", x, y,
1056 // infoPtr->prevmonth.left, infoPtr->prevmonth.right,
1057 // infoPtr->prevmonth.top, infoPtr->prevmonth.bottom,
1058 // infoPtr->nextmonth.left, infoPtr->nextmonth.right,
1059 // infoPtr->nextmonth.top, infoPtr->nextmonth.bottom);
1060 if((x>infoPtr->prevmonth.left) &&(x<infoPtr->nextmonth.right) &&
1061 (y>infoPtr->prevmonth.top) &&(y<infoPtr->nextmonth.bottom)) {
1062 lpht->st.wYear = infoPtr->currentYear;
1063 lpht->st.wMonth = infoPtr->currentMonth;
1064
1065 lpht->st.wDay = MONTHCAL_CalcDayFromPos(infoPtr, x, y);
1066
1067 //TRACE("day hit: %d\n", lpht->st.wDay);
1068 retval = MCHT_CALENDARDATE;
1069 goto done;
1070
1071 }
1072
1073 /* Hit nothing special? What's left must be background :-) */
1074
1075 retval = MCHT_CALENDARBK;
1076 done:
1077 lpht->uHit = retval;
1078 return retval;
1079}
1080
1081
1082static void MONTHCAL_GoToNextMonth(HWND hwnd, MONTHCAL_INFO *infoPtr)
1083{
1084 DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
1085
1086 //TRACE("MONTHCAL_GoToNextMonth\n");
1087
1088 infoPtr->currentMonth++;
1089 if(infoPtr->currentMonth > 12) {
1090 infoPtr->currentYear++;
1091 infoPtr->currentMonth = 1;
1092 }
1093
1094 if(dwStyle & MCS_DAYSTATE) {
1095 NMDAYSTATE nmds;
1096 int i;
1097
1098 nmds.cDayState = infoPtr->monthRange;
1099 nmds.prgDayState = (DWORD*)COMCTL32_Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE));
1100
1101 sendNotify(hwnd,MCN_GETDAYSTATE,&nmds.nmhdr);
1102 for(i=0; i<infoPtr->monthRange; i++)
1103 infoPtr->monthdayState[i] = nmds.prgDayState[i];
1104 }
1105}
1106
1107
1108static void MONTHCAL_GoToPrevMonth(HWND hwnd, MONTHCAL_INFO *infoPtr)
1109{
1110 DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
1111
1112 //TRACE("MONTHCAL_GoToPrevMonth\n");
1113
1114 infoPtr->currentMonth--;
1115 if(infoPtr->currentMonth < 1) {
1116 infoPtr->currentYear--;
1117 infoPtr->currentMonth = 12;
1118 }
1119
1120 if(dwStyle & MCS_DAYSTATE) {
1121 NMDAYSTATE nmds;
1122 int i;
1123
1124 nmds.cDayState = infoPtr->monthRange;
1125 nmds.prgDayState = (DWORD*)COMCTL32_Alloc
1126 (infoPtr->monthRange * sizeof(MONTHDAYSTATE));
1127
1128 sendNotify(hwnd,MCN_GETDAYSTATE,&nmds.nmhdr);
1129 for(i=0; i<infoPtr->monthRange; i++)
1130 infoPtr->monthdayState[i] = nmds.prgDayState[i];
1131 }
1132}
1133
1134
1135static LRESULT
1136MONTHCAL_LButtonDown(HWND hwnd, WPARAM wParam, LPARAM lParam)
1137{
1138 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
1139 MCHITTESTINFO ht;
1140 HDC hdc;
1141 DWORD hit;
1142 HMENU hMenu;
1143 HWND retval;
1144 BOOL redraw = FALSE;
1145
1146
1147 //TRACE("%x %lx\n", wParam, lParam);
1148
1149 ht.pt.x = (INT)LOWORD(lParam);
1150 ht.pt.y = (INT)HIWORD(lParam);
1151 hit = MONTHCAL_HitTest(hwnd, (LPARAM)&ht);
1152
1153 /* FIXME: these flags should be checked by */
1154 /*((hit & MCHT_XXX) == MCHT_XXX) b/c some of the flags are */
1155 /* multi-bit */
1156 if(hit & MCHT_NEXT) {
1157 redraw = TRUE;
1158 MONTHCAL_GoToNextMonth(hwnd, infoPtr);
1159 infoPtr->status = MC_NEXTPRESSED;
1160 SetTimer(hwnd, MC_NEXTMONTHTIMER, MC_NEXTMONTHDELAY, 0);
1161 }
1162 if(hit & MCHT_PREV) {
1163 redraw = TRUE;
1164 MONTHCAL_GoToPrevMonth(hwnd, infoPtr);
1165 infoPtr->status = MC_PREVPRESSED;
1166 SetTimer(hwnd, MC_PREVMONTHTIMER, MC_NEXTMONTHDELAY, 0);
1167 }
1168
1169 if(hit == MCHT_TITLEMONTH) {
1170/*
1171 HRSRC hrsrc = FindResourceA( COMCTL32_hModule, MAKEINTRESOURCEA(IDD_MCMONTHMENU), RT_MENUA );
1172 if(!hrsrc) {
1173 TRACE("returning zero\n");
1174 return 0;
1175 }
1176 TRACE("resource is:%x\n",hrsrc);
1177 hMenu = LoadMenuIndirectA((LPCVOID)LoadResource( COMCTL32_hModule, hrsrc ));
1178
1179 TRACE("menu is:%x\n",hMenu);
1180*/
1181
1182 hMenu = CreateMenu();
1183 AppendMenuA(hMenu, MF_STRING,IDM_JAN, "January");
1184 AppendMenuA(hMenu, MF_STRING,IDM_FEB, "February");
1185 AppendMenuA(hMenu, MF_STRING,IDM_MAR, "March");
1186
1187 retval = CreateWindowA(POPUPMENU_CLASS_ATOM, NULL,
1188 WS_CHILD | WS_VISIBLE, 0, 0 ,100 , 220,
1189 hwnd, hMenu, GetWindowLongA(hwnd, GWL_HINSTANCE), NULL);
1190 //TRACE("hwnd returned:%x\n", retval);
1191
1192 }
1193 if(hit == MCHT_TITLEYEAR) {
1194 //FIXME("create updown for yearselection\n");
1195 }
1196 if(hit == MCHT_TODAYLINK) {
1197 //FIXME("set currentday\n");
1198 }
1199 if(hit == MCHT_CALENDARDATE) {
1200 SYSTEMTIME selArray[2];
1201 NMSELCHANGE nmsc;
1202
1203 //TRACE("\n");
1204 MONTHCAL_CopyTime(&nmsc.stSelStart, &infoPtr->minSel);
1205 MONTHCAL_CopyTime(&nmsc.stSelEnd, &infoPtr->maxSel);
1206
1207 sendNotify(hwnd,MCN_SELCHANGE,&nmsc.nmhdr);
1208
1209 MONTHCAL_CopyTime(&ht.st, &selArray[0]);
1210 MONTHCAL_CopyTime(&ht.st, &selArray[1]);
1211 MONTHCAL_SetSelRange(hwnd,0,(LPARAM) &selArray);
1212
1213 /* redraw if the selected day changed */
1214 if(infoPtr->curSelDay != ht.st.wDay) {
1215 redraw = TRUE;
1216 }
1217
1218 infoPtr->firstSelDay = ht.st.wDay;
1219 infoPtr->curSelDay = ht.st.wDay;
1220 infoPtr->status = MC_SEL_LBUTDOWN;
1221 }
1222
1223 /* redraw only if the control changed */
1224 if(redraw) {
1225 hdc = GetDC(hwnd);
1226 MONTHCAL_Refresh(hwnd, hdc);
1227 ReleaseDC(hwnd, hdc);
1228 }
1229
1230 return 0;
1231}
1232
1233
1234static LRESULT
1235MONTHCAL_LButtonUp(HWND hwnd, WPARAM wParam, LPARAM lParam)
1236{
1237 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
1238 NMSELCHANGE nmsc;
1239 HDC hdc;
1240 BOOL redraw = FALSE;
1241
1242 //TRACE("\n");
1243
1244 if(infoPtr->status & MC_NEXTPRESSED) {
1245 KillTimer(hwnd, MC_NEXTMONTHTIMER);
1246 redraw = TRUE;
1247 }
1248 if(infoPtr->status & MC_PREVPRESSED) {
1249 KillTimer(hwnd, MC_PREVMONTHTIMER);
1250 redraw = TRUE;
1251 }
1252
1253 infoPtr->status = MC_SEL_LBUTUP;
1254
1255 sendNotify(hwnd,NM_RELEASEDCAPTURE);
1256
1257 MONTHCAL_CopyTime(&nmsc.stSelStart, &infoPtr->minSel);
1258 MONTHCAL_CopyTime(&nmsc.stSelEnd, &infoPtr->maxSel);
1259
1260 sendNotify(hwnd,MCN_SELECT,&nmsc.nmhdr);
1261
1262 /* redraw if necessary */
1263 if(redraw) {
1264 hdc = GetDC(hwnd);
1265 MONTHCAL_Refresh(hwnd, hdc);
1266 ReleaseDC(hwnd, hdc);
1267 }
1268
1269 return 0;
1270}
1271
1272
1273static LRESULT
1274MONTHCAL_Timer(HWND hwnd, WPARAM wParam, LPARAM lParam)
1275{
1276 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
1277 HDC hdc;
1278 BOOL redraw = FALSE;
1279
1280 //TRACE(" %d\n", wParam);
1281 if(!infoPtr) return 0;
1282
1283 switch(wParam) {
1284 case MC_NEXTMONTHTIMER:
1285 redraw = TRUE;
1286 MONTHCAL_GoToNextMonth(hwnd, infoPtr);
1287 break;
1288 case MC_PREVMONTHTIMER:
1289 redraw = TRUE;
1290 MONTHCAL_GoToPrevMonth(hwnd, infoPtr);
1291 break;
1292 //default:
1293 // ERR("got unknown timer\n");
1294 }
1295
1296 /* redraw only if necessary */
1297 if(redraw) {
1298 hdc = GetDC(hwnd);
1299 MONTHCAL_Refresh(hwnd, hdc);
1300 ReleaseDC(hwnd, hdc);
1301 }
1302
1303 return 0;
1304}
1305
1306
1307static LRESULT
1308MONTHCAL_MouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
1309{
1310 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
1311 MCHITTESTINFO ht;
1312 HDC hdc;
1313 int oldselday, selday, hit;
1314 RECT r;
1315
1316 if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0;
1317
1318 ht.pt.x = LOWORD(lParam);
1319 ht.pt.y = HIWORD(lParam);
1320
1321 hit = MONTHCAL_HitTest(hwnd, (LPARAM)&ht);
1322
1323 /* not on the calendar date numbers? bail out */
1324 //TRACE("hit:%x\n",hit);
1325 if((hit & MCHT_CALENDARDATE) != MCHT_CALENDARDATE) return 0;
1326
1327 selday = ht.st.wDay;
1328 oldselday = infoPtr->curSelDay;
1329 infoPtr->curSelDay = selday;
1330 MONTHCAL_CalcPosFromDay(infoPtr, selday, ht.st. wMonth, &r);
1331
1332 if(GetWindowLongA(hwnd, GWL_STYLE) & MCS_MULTISELECT) {
1333 SYSTEMTIME selArray[2];
1334 int i;
1335
1336 MONTHCAL_GetSelRange(hwnd, 0, (LPARAM)&selArray);
1337 i = 0;
1338 if(infoPtr->firstSelDay==selArray[0].wDay) i=1;
1339 //TRACE("oldRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i);
1340 if(infoPtr->firstSelDay==selArray[1].wDay) {
1341 /* 1st time we get here: selArray[0]=selArray[1]) */
1342 /* if we're still at the first selected date, return */
1343 if(infoPtr->firstSelDay==selday) goto done;
1344 if(selday<infoPtr->firstSelDay) i = 0;
1345 }
1346
1347 if(abs(infoPtr->firstSelDay - selday) >= infoPtr->maxSelCount) {
1348 if(selday>infoPtr->firstSelDay)
1349 selday = infoPtr->firstSelDay + infoPtr->maxSelCount;
1350 else
1351 selday = infoPtr->firstSelDay - infoPtr->maxSelCount;
1352 }
1353
1354 if(selArray[i].wDay!=selday) {
1355 //TRACE("newRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i);
1356
1357 selArray[i].wDay = selday;
1358
1359 if(selArray[0].wDay>selArray[1].wDay) {
1360 DWORD tempday;
1361 tempday = selArray[1].wDay;
1362 selArray[1].wDay = selArray[0].wDay;
1363 selArray[0].wDay = tempday;
1364 }
1365
1366 MONTHCAL_SetSelRange(hwnd, 0, (LPARAM)&selArray);
1367 }
1368 }
1369
1370done:
1371
1372 /* only redraw if the currently selected day changed */
1373 if(oldselday != infoPtr->curSelDay) {
1374 hdc = GetDC(hwnd);
1375 MONTHCAL_Refresh(hwnd, hdc);
1376 ReleaseDC(hwnd, hdc);
1377 }
1378
1379 return 0;
1380}
1381
1382
1383static LRESULT
1384MONTHCAL_Paint(HWND hwnd, WPARAM wParam)
1385{
1386 HDC hdc;
1387 PAINTSTRUCT ps;
1388
1389 hdc = (wParam==0 ? BeginPaint(hwnd, &ps) : (HDC)wParam);
1390 MONTHCAL_Refresh(hwnd, hdc);
1391 if(!wParam) EndPaint(hwnd, &ps);
1392 return 0;
1393}
1394
1395
1396static LRESULT
1397MONTHCAL_KillFocus(HWND hwnd, WPARAM wParam, LPARAM lParam)
1398{
1399 HDC hdc;
1400
1401 //TRACE("\n");
1402
1403 hdc = GetDC(hwnd);
1404 MONTHCAL_Refresh(hwnd, hdc);
1405 ReleaseDC(hwnd, hdc);
1406 InvalidateRect(hwnd, NULL, TRUE);
1407
1408 return 0;
1409}
1410
1411
1412static LRESULT
1413MONTHCAL_SetFocus(HWND hwnd, WPARAM wParam, LPARAM lParam)
1414{
1415 HDC hdc;
1416
1417 //TRACE("\n");
1418
1419 hdc = GetDC(hwnd);
1420 MONTHCAL_Refresh(hwnd, hdc);
1421 ReleaseDC(hwnd, hdc);
1422
1423 return 0;
1424}
1425
1426/* sets the size information */
1427static void MONTHCAL_UpdateSize(HWND hwnd)
1428{
1429 HDC hdc = GetDC(hwnd);
1430 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
1431 RECT *rcClient=&infoPtr->rcClient;
1432 RECT *rcDraw=&infoPtr->rcDraw;
1433 RECT *title=&infoPtr->title;
1434 RECT *prev=&infoPtr->titlebtnprev;
1435 RECT *next=&infoPtr->titlebtnnext;
1436 RECT *titlemonth=&infoPtr->titlemonth;
1437 RECT *titleyear=&infoPtr->titleyear;
1438 RECT *days=&infoPtr->days;
1439 SIZE size;
1440 TEXTMETRICA tm;
1441 DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
1442 HFONT currentFont;
1443
1444 currentFont = SelectObject(hdc, infoPtr->hFont);
1445
1446 /* FIXME: need a way to determine current font, without setting it */
1447 /*
1448 if(infoPtr->hFont!=currentFont) {
1449 SelectObject(hdc, currentFont);
1450 infoPtr->hFont=currentFont;
1451 GetObjectA(currentFont, sizeof(LOGFONTA), &logFont);
1452 logFont.lfWeight=FW_BOLD;
1453 infoPtr->hBoldFont = CreateFontIndirectA(&logFont);
1454 }
1455 */
1456
1457 /* get the height and width of each day's text */
1458 GetTextMetricsA(hdc, &tm);
1459 infoPtr->textHeight = tm.tmHeight + tm.tmExternalLeading;
1460 GetTextExtentPoint32A(hdc, "Sun", 3, &size);
1461 infoPtr->textWidth = size.cx + 2;
1462
1463 /* retrieve the controls client rectangle info infoPtr->rcClient */
1464 GetClientRect(hwnd, rcClient);
1465
1466 if(dwStyle & MCS_WEEKNUMBERS)
1467 infoPtr->rcClient.right+=infoPtr->textWidth;
1468
1469 /* rcDraw is the rectangle the control is drawn in */
1470 rcDraw->left = rcClient->left;
1471 rcDraw->right = rcClient->right;
1472 rcDraw->top = rcClient->top;
1473 rcDraw->bottom = rcClient->bottom;
1474
1475 /* use DrawEdge to adjust the size of rcClient such that we */
1476 /* do not overwrite the border when drawing the control */
1477 DrawEdge((HDC)NULL, rcDraw, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1478
1479
1480 /* this is correct, the control does NOT expand vertically */
1481 /* like it does horizontally */
1482 /* make sure we don't move the controls bottom out of the client */
1483 /* area */
1484 if((rcDraw->top + 8 * infoPtr->textHeight + 5) < rcDraw->bottom) {
1485 rcDraw->bottom = rcDraw->top + 8 * infoPtr->textHeight + 5;
1486 }
1487
1488 /* calculate title area */
1489 title->top = rcClient->top + 1;
1490 title->bottom = title->top + 2 * infoPtr->textHeight + 4;
1491 title->left = rcClient->left + 1;
1492 title->right = rcClient->right - 1;
1493
1494 /* recalculate the height and width increments and offsets */
1495 infoPtr->width_increment = (infoPtr->rcDraw.right - infoPtr->rcDraw.left) / 7.0;
1496 infoPtr->height_increment = (infoPtr->rcDraw.bottom - infoPtr->rcDraw.top) / 7.0;
1497 infoPtr->left_offset = (infoPtr->rcDraw.right - infoPtr->rcDraw.left) - (infoPtr->width_increment * 7.0);
1498 infoPtr->top_offset = (infoPtr->rcDraw.bottom - infoPtr->rcDraw.top) - (infoPtr->height_increment * 7.0);
1499
1500 /* set the dimensions of the next and previous buttons and center */
1501 /* the month text vertically */
1502 prev->top = next->top = title->top + 6;
1503 prev->bottom = next->bottom = title->top + 2 * infoPtr->textHeight - 3;
1504 prev->right = title->left + 28;
1505 prev->left = title->left + 4;
1506 next->left = title->right - 28;
1507 next->right = title->right - 4;
1508
1509 /* titlemonth->left and right change based upon the current month */
1510 /* and are recalculated in refresh as the current month may change */
1511 /* without the control being resized */
1512 titlemonth->bottom = titleyear->bottom = prev->top + 2 * infoPtr->textHeight - 3;
1513 titlemonth->top = titleyear->top = title->top;
1514
1515 /* setup the dimensions of the rectangle we draw the names of the */
1516 /* days of the week in */
1517 days->left = infoPtr->left_offset;
1518 if(dwStyle & MCS_WEEKNUMBERS) days->left+=infoPtr->textWidth;
1519 days->right = days->left + infoPtr->width_increment;
1520 days->top = title->bottom + 2;
1521 days->bottom = title->bottom + infoPtr->textHeight + 2;
1522
1523 /* restore the originally selected font */
1524 SelectObject(hdc, currentFont);
1525
1526 ReleaseDC(hwnd, hdc);
1527}
1528
1529static LRESULT MONTHCAL_Size(HWND hwnd, int Width, int Height)
1530{
1531 //TRACE("(hwnd=%x, width=%d, height=%d)\n", hwnd, Width, Height);
1532
1533 MONTHCAL_UpdateSize(hwnd);
1534
1535 /* invalidate client area and erase background */
1536 InvalidateRect(hwnd, NULL, TRUE);
1537
1538 return 0;
1539}
1540
1541/* FIXME: check whether dateMin/dateMax need to be adjusted. */
1542static LRESULT
1543MONTHCAL_Create(HWND hwnd, WPARAM wParam, LPARAM lParam)
1544{
1545 MONTHCAL_INFO *infoPtr;
1546 LOGFONTA logFont;
1547
1548 /* allocate memory for info structure */
1549 infoPtr =(MONTHCAL_INFO*)initControl(hwnd,sizeof(MONTHCAL_INFO));
1550
1551 if(infoPtr == NULL) {
1552 //ERR( "could not allocate info memory!\n");
1553 return 0;
1554 }
1555 if((MONTHCAL_INFO*)GetWindowLongA(hwnd, 0) != infoPtr) {
1556 //ERR( "pointer assignment error!\n");
1557 return 0;
1558 }
1559
1560 infoPtr->hFont = GetStockObject(DEFAULT_GUI_FONT);
1561 GetObjectA(infoPtr->hFont, sizeof(LOGFONTA), &logFont);
1562 logFont.lfWeight = FW_BOLD;
1563 infoPtr->hBoldFont = CreateFontIndirectA(&logFont);
1564
1565 /* initialize info structure */
1566 /* FIXME: calculate systemtime ->> localtime(substract timezoneinfo) */
1567
1568 GetSystemTime(&infoPtr->todaysDate);
1569 infoPtr->firstDay = 0;
1570 infoPtr->currentMonth = infoPtr->todaysDate.wMonth;
1571 infoPtr->currentYear = infoPtr->todaysDate.wYear;
1572 MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minDate);
1573 MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate);
1574 infoPtr->maxSelCount = 6;
1575 infoPtr->monthRange = 3;
1576 infoPtr->monthdayState = (MONTHDAYSTATE*)COMCTL32_Alloc
1577 (infoPtr->monthRange * sizeof(MONTHDAYSTATE));
1578 infoPtr->titlebk = GetSysColor(COLOR_ACTIVECAPTION);
1579 infoPtr->titletxt = GetSysColor(COLOR_WINDOW);
1580 infoPtr->monthbk = GetSysColor(COLOR_WINDOW);
1581 infoPtr->trailingtxt = GetSysColor(COLOR_GRAYTEXT);
1582 infoPtr->bk = GetSysColor(COLOR_WINDOW);
1583 infoPtr->txt = GetSysColor(COLOR_WINDOWTEXT);
1584
1585 /* call MONTHCAL_UpdateSize to set all of the dimensions */
1586 /* of the control */
1587 MONTHCAL_UpdateSize(hwnd);
1588
1589 return 0;
1590}
1591
1592
1593static LRESULT
1594MONTHCAL_Destroy(HWND hwnd, WPARAM wParam, LPARAM lParam)
1595{
1596 MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
1597
1598 /* free month calendar info data */
1599 doneControl(hwnd);
1600
1601 return 0;
1602}
1603
1604
1605static LRESULT WINAPI
1606MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1607{
1608 switch(uMsg)
1609 {
1610 case MCM_GETCURSEL:
1611 return MONTHCAL_GetCurSel(hwnd, wParam, lParam);
1612
1613 case MCM_SETCURSEL:
1614 return MONTHCAL_SetCurSel(hwnd, wParam, lParam);
1615
1616 case MCM_GETMAXSELCOUNT:
1617 return MONTHCAL_GetMaxSelCount(hwnd, wParam, lParam);
1618
1619 case MCM_SETMAXSELCOUNT:
1620 return MONTHCAL_SetMaxSelCount(hwnd, wParam, lParam);
1621
1622 case MCM_GETSELRANGE:
1623 return MONTHCAL_GetSelRange(hwnd, wParam, lParam);
1624
1625 case MCM_SETSELRANGE:
1626 return MONTHCAL_SetSelRange(hwnd, wParam, lParam);
1627
1628 case MCM_GETMONTHRANGE:
1629 return MONTHCAL_GetMonthRange(hwnd, wParam, lParam);
1630
1631 case MCM_SETDAYSTATE:
1632 return MONTHCAL_SetDayState(hwnd, wParam, lParam);
1633
1634 case MCM_GETMINREQRECT:
1635 return MONTHCAL_GetMinReqRect(hwnd, wParam, lParam);
1636
1637 case MCM_GETCOLOR:
1638 return MONTHCAL_GetColor(hwnd, wParam, lParam);
1639
1640 case MCM_SETCOLOR:
1641 return MONTHCAL_SetColor(hwnd, wParam, lParam);
1642
1643 case MCM_GETTODAY:
1644 return MONTHCAL_GetToday(hwnd, wParam, lParam);
1645
1646 case MCM_SETTODAY:
1647 return MONTHCAL_SetToday(hwnd, wParam, lParam);
1648
1649 case MCM_HITTEST:
1650 return MONTHCAL_HitTest(hwnd,lParam);
1651
1652 case MCM_GETFIRSTDAYOFWEEK:
1653 return MONTHCAL_GetFirstDayOfWeek(hwnd, wParam, lParam);
1654
1655 case MCM_SETFIRSTDAYOFWEEK:
1656 return MONTHCAL_SetFirstDayOfWeek(hwnd, wParam, lParam);
1657
1658 case MCM_GETRANGE:
1659 return MONTHCAL_GetRange(hwnd, wParam, lParam);
1660
1661 case MCM_SETRANGE:
1662 return MONTHCAL_SetRange(hwnd, wParam, lParam);
1663
1664 case MCM_GETMONTHDELTA:
1665 return MONTHCAL_GetMonthDelta(hwnd, wParam, lParam);
1666
1667 case MCM_SETMONTHDELTA:
1668 return MONTHCAL_SetMonthDelta(hwnd, wParam, lParam);
1669
1670 case MCM_GETMAXTODAYWIDTH:
1671 return MONTHCAL_GetMaxTodayWidth(hwnd);
1672
1673 case WM_GETDLGCODE:
1674 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1675
1676 case WM_KILLFOCUS:
1677 return MONTHCAL_KillFocus(hwnd, wParam, lParam);
1678
1679 case WM_LBUTTONDOWN:
1680 return MONTHCAL_LButtonDown(hwnd, wParam, lParam);
1681
1682 case WM_MOUSEMOVE:
1683 return MONTHCAL_MouseMove(hwnd, wParam, lParam);
1684
1685 case WM_LBUTTONUP:
1686 return MONTHCAL_LButtonUp(hwnd, wParam, lParam);
1687
1688 case WM_PAINT:
1689 return MONTHCAL_Paint(hwnd, wParam);
1690
1691 case WM_SETFOCUS:
1692 return MONTHCAL_SetFocus(hwnd, wParam, lParam);
1693
1694 case WM_SIZE:
1695 return MONTHCAL_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
1696
1697 case WM_CREATE:
1698 return MONTHCAL_Create(hwnd, wParam, lParam);
1699
1700 case WM_TIMER:
1701 return MONTHCAL_Timer(hwnd, wParam, lParam);
1702
1703 case WM_DESTROY:
1704 return MONTHCAL_Destroy(hwnd, wParam, lParam);
1705
1706 default:
1707 //if(uMsg >= WM_USER)
1708 // ERR( "unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam);
1709 return defComCtl32ProcA(hwnd, uMsg, wParam, lParam);
1710 }
1711 return 0;
1712}
1713
1714
1715void
1716MONTHCAL_Register(void)
1717{
1718 WNDCLASSA wndClass;
1719
1720 ZeroMemory(&wndClass, sizeof(WNDCLASSA));
1721 wndClass.style = CS_GLOBALCLASS;
1722 wndClass.lpfnWndProc = (WNDPROC)MONTHCAL_WindowProc;
1723 wndClass.cbClsExtra = 0;
1724 wndClass.cbWndExtra = sizeof(MONTHCAL_INFO *);
1725 wndClass.hCursor = LoadCursorA(0, IDC_ARROWA);
1726 wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
1727 wndClass.lpszClassName = MONTHCAL_CLASSA;
1728
1729 RegisterClassA(&wndClass);
1730}
1731
1732
1733void
1734MONTHCAL_Unregister(void)
1735{
1736 UnregisterClassA(MONTHCAL_CLASSA, (HINSTANCE)NULL);
1737}
Note: See TracBrowser for help on using the repository browser.