ReactOS  0.4.14-dev-606-g14ebc0b
monthcal.c
Go to the documentation of this file.
1 /*
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 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
9  * Copyright 2009-2011 Nikolay Sivov
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  *
25  * TODO:
26  * -- MCM_[GS]ETUNICODEFORMAT
27  * -- handle resources better (doesn't work now);
28  * -- take care of internationalization.
29  * -- keyboard handling.
30  * -- search for FIXME
31  */
32 
33 #include <math.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "windef.h"
40 #include "winbase.h"
41 #include "wingdi.h"
42 #include "winuser.h"
43 #include "winnls.h"
44 #include "commctrl.h"
45 #include "comctl32.h"
46 #include "uxtheme.h"
47 #include "vssym32.h"
48 #include "wine/unicode.h"
49 #include "wine/debug.h"
50 #include "wine/heap.h"
51 
53 
54 /* FIXME: Inspect */
55 #define MCS_NOSELCHANGEONNAV 0x0100
56 
57 #define MC_SEL_LBUTUP 1 /* Left button released */
58 #define MC_SEL_LBUTDOWN 2 /* Left button pressed in calendar */
59 #define MC_PREVPRESSED 4 /* Prev month button pressed */
60 #define MC_NEXTPRESSED 8 /* Next month button pressed */
61 #define MC_PREVNEXTMONTHDELAY 350 /* when continuously pressing `next/prev
62  month', wait 350 ms before going
63  to the next/prev month */
64 #define MC_TODAYUPDATEDELAY 120000 /* time between today check for update (2 min) */
65 
66 #define MC_PREVNEXTMONTHTIMER 1 /* Timer IDs */
67 #define MC_TODAYUPDATETIMER 2
68 
69 #define MC_CALENDAR_PADDING 6
70 
71 /* convert from days to 100 nanoseconds unit - used as FILETIME unit */
72 #define DAYSTO100NSECS(days) (((ULONGLONG)(days))*24*60*60*10000000)
73 
75 {
76  PenRed = 0,
79 };
80 
82 {
87 };
88 
89 /* single calendar data */
90 typedef struct _CALENDAR_INFO
91 {
92  RECT title; /* rect for the header above the calendar */
93  RECT titlemonth; /* the 'month name' text in the header */
94  RECT titleyear; /* the 'year number' text in the header */
95  RECT wdays; /* week days at top */
96  RECT days; /* calendar area */
97  RECT weeknums; /* week numbers at left side */
98 
99  SYSTEMTIME month;/* contains calendar main month/year */
100 } CALENDAR_INFO;
101 
102 typedef struct
103 {
105  DWORD dwStyle; /* cached GWL_STYLE */
106 
108  HBRUSH brushes[BrushLast];
109  HPEN pens[PenLast];
110 
116  INT delta; /* scroll rate; # of months that the */
117  /* control moves when user clicks a scroll button */
118  int firstDay; /* Start month calendar with firstDay's day,
119  stored in SYSTEMTIME format */
120  BOOL firstDaySet; /* first week day differs from locale defined */
121 
122  BOOL isUnicode; /* value set with MCM_SETUNICODE format */
123 
126  BOOL todaySet; /* Today was forced with MCM_SETTODAY */
127  int status; /* See MC_SEL flags */
128  SYSTEMTIME firstSel; /* first selected day */
130  SYSTEMTIME minSel; /* contains single selection when used without MCS_MULTISELECT */
132  SYSTEMTIME focusedSel; /* date currently focused with mouse movement */
136 
137  RECT titlebtnnext; /* the `next month' button in the header */
138  RECT titlebtnprev; /* the `prev month' button in the header */
139  RECT todayrect; /* `today: xx/xx/xx' text rect */
140  HWND hwndNotify; /* Window to receive the notifications */
141  HWND hWndYearEdit; /* Window Handle of edit box to handle years */
142  HWND hWndYearUpDown;/* Window Handle of updown box to handle years */
143  WNDPROC EditWndProc; /* original Edit window procedure */
144 
146  SIZE dim; /* [cx,cy] - dimensions of calendars matrix, row/column count */
148 
149 static const WCHAR themeClass[] = { 'S','c','r','o','l','l','b','a','r',0 };
150 
151 /* empty SYSTEMTIME const */
152 static const SYSTEMTIME st_null;
153 /* valid date limits */
154 static const SYSTEMTIME max_allowed_date = { /* wYear */ 9999, /* wMonth */ 12, /* wDayOfWeek */ 0, /* wDay */ 31 };
155 static const SYSTEMTIME min_allowed_date = { /* wYear */ 1752, /* wMonth */ 9, /* wDayOfWeek */ 0, /* wDay */ 14 };
156 
157 /* Prev/Next buttons */
159 {
162 };
163 
164 /* helper functions */
165 static inline INT MONTHCAL_GetCalCount(const MONTHCAL_INFO *infoPtr)
166 {
167  return infoPtr->dim.cx * infoPtr->dim.cy;
168 }
169 
170 /* send a single MCN_SELCHANGE notification */
171 static inline void MONTHCAL_NotifySelectionChange(const MONTHCAL_INFO *infoPtr)
172 {
173  NMSELCHANGE nmsc;
174 
175  nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
176  nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
177  nmsc.nmhdr.code = MCN_SELCHANGE;
178  nmsc.stSelStart = infoPtr->minSel;
179  nmsc.stSelStart.wDayOfWeek = 0;
180  if(infoPtr->dwStyle & MCS_MULTISELECT){
181  nmsc.stSelEnd = infoPtr->maxSel;
182  nmsc.stSelEnd.wDayOfWeek = 0;
183  }
184  else
185  nmsc.stSelEnd = st_null;
186 
187  SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
188 }
189 
190 /* send a single MCN_SELECT notification */
191 static inline void MONTHCAL_NotifySelect(const MONTHCAL_INFO *infoPtr)
192 {
193  NMSELCHANGE nmsc;
194 
195  nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
196  nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
197  nmsc.nmhdr.code = MCN_SELECT;
198  nmsc.stSelStart = infoPtr->minSel;
199  nmsc.stSelStart.wDayOfWeek = 0;
200  if(infoPtr->dwStyle & MCS_MULTISELECT){
201  nmsc.stSelEnd = infoPtr->maxSel;
202  nmsc.stSelEnd.wDayOfWeek = 0;
203  }
204  else
205  nmsc.stSelEnd = st_null;
206 
207  SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
208 }
209 
210 static inline int MONTHCAL_MonthDiff(const SYSTEMTIME *left, const SYSTEMTIME *right)
211 {
212  return (right->wYear - left->wYear)*12 + right->wMonth - left->wMonth;
213 }
214 
215 /* returns the number of days in any given month, checking for leap days */
216 /* January is 1, December is 12 */
217 int MONTHCAL_MonthLength(int month, int year)
218 {
219  const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
220  /* Wrap around, this eases handling. Getting length only we shouldn't care
221  about year change here cause January and December have
222  the same day quantity */
223  if(month == 0)
224  month = 12;
225  else if(month == 13)
226  month = 1;
227 
228  /* special case for calendar transition year */
229  if(month == min_allowed_date.wMonth && year == min_allowed_date.wYear) return 19;
230 
231  /* if we have a leap year add 1 day to February */
232  /* a leap year is a year either divisible by 400 */
233  /* or divisible by 4 and not by 100 */
234  if(month == 2) { /* February */
235  return mdays[month - 1] + ((year%400 == 0) ? 1 : ((year%100 != 0) &&
236  (year%4 == 0)) ? 1 : 0);
237  }
238  else {
239  return mdays[month - 1];
240  }
241 }
242 
243 /* compares timestamps using date part only */
244 static inline BOOL MONTHCAL_IsDateEqual(const SYSTEMTIME *first, const SYSTEMTIME *second)
245 {
246  return (first->wYear == second->wYear) && (first->wMonth == second->wMonth) &&
247  (first->wDay == second->wDay);
248 }
249 
250 /* make sure that date fields are valid */
252 {
253  if (time->wMonth < 1 || time->wMonth > 12 )
254  return FALSE;
255  if (time->wDay == 0 || time->wDay > MONTHCAL_MonthLength(time->wMonth, time->wYear))
256  return FALSE;
257 
258  return TRUE;
259 }
260 
261 /* Copies timestamp part only.
262  *
263  * PARAMETERS
264  *
265  * [I] from : source date
266  * [O] to : dest date
267  */
268 static void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to)
269 {
270  to->wHour = from->wHour;
271  to->wMinute = from->wMinute;
272  to->wSecond = from->wSecond;
273 }
274 
275 /* Copies date part only.
276  *
277  * PARAMETERS
278  *
279  * [I] from : source date
280  * [O] to : dest date
281  */
282 static void MONTHCAL_CopyDate(const SYSTEMTIME *from, SYSTEMTIME *to)
283 {
284  to->wYear = from->wYear;
285  to->wMonth = from->wMonth;
286  to->wDay = from->wDay;
287  to->wDayOfWeek = from->wDayOfWeek;
288 }
289 
290 /* Compares two dates in SYSTEMTIME format
291  *
292  * PARAMETERS
293  *
294  * [I] first : pointer to valid first date data to compare
295  * [I] second : pointer to valid second date data to compare
296  *
297  * RETURN VALUE
298  *
299  * -1 : first < second
300  * 0 : first == second
301  * 1 : first > second
302  *
303  * Note that no date validation performed, already validated values expected.
304  */
306 {
307  FILETIME ft_first, ft_second;
308 
309  SystemTimeToFileTime(first, &ft_first);
310  SystemTimeToFileTime(second, &ft_second);
311 
312  return CompareFileTime(&ft_first, &ft_second);
313 }
314 
316 {
317  SYSTEMTIME st_first, st_second;
318 
319  st_first = st_second = st_null;
320  MONTHCAL_CopyDate(first, &st_first);
321  MONTHCAL_CopyDate(second, &st_second);
322  st_first.wDay = st_second.wDay = 1;
323 
324  return MONTHCAL_CompareSystemTime(&st_first, &st_second);
325 }
326 
327 static LONG MONTHCAL_CompareDate(const SYSTEMTIME *first, const SYSTEMTIME *second)
328 {
329  SYSTEMTIME st_first, st_second;
330 
331  st_first = st_second = st_null;
332  MONTHCAL_CopyDate(first, &st_first);
333  MONTHCAL_CopyDate(second, &st_second);
334 
335  return MONTHCAL_CompareSystemTime(&st_first, &st_second);
336 }
337 
338 /* Checks largest possible date range and configured one
339  *
340  * PARAMETERS
341  *
342  * [I] infoPtr : valid pointer to control data
343  * [I] date : pointer to valid date data to check
344  * [I] fix : make date fit valid range
345  *
346  * RETURN VALUE
347  *
348  * TRUE - date within largest and configured range
349  * FALSE - date is outside largest or configured range
350  */
352  SYSTEMTIME *date, BOOL fix)
353 {
354  const SYSTEMTIME *fix_st = NULL;
355 
357  fix_st = &max_allowed_date;
358  }
360  fix_st = &min_allowed_date;
361  }
362  else {
363  if(infoPtr->rangeValid & GDTR_MAX) {
364  if((MONTHCAL_CompareSystemTime(date, &infoPtr->maxDate) == 1)) {
365  fix_st = &infoPtr->maxDate;
366  }
367  }
368 
369  if(infoPtr->rangeValid & GDTR_MIN) {
370  if((MONTHCAL_CompareSystemTime(date, &infoPtr->minDate) == -1)) {
371  fix_st = &infoPtr->minDate;
372  }
373  }
374  }
375 
376  if (fix && fix_st) {
377  date->wYear = fix_st->wYear;
378  date->wMonth = fix_st->wMonth;
379  }
380 
381  return !fix_st;
382 }
383 
384 /* Checks passed range width with configured maximum selection count
385  *
386  * PARAMETERS
387  *
388  * [I] infoPtr : valid pointer to control data
389  * [I] range0 : pointer to valid date data (requested bound)
390  * [I] range1 : pointer to valid date data (primary bound)
391  * [O] adjust : returns adjusted range bound to fit maximum range (optional)
392  *
393  * Adjust value computed basing on primary bound and current maximum selection
394  * count. For simple range check (without adjusted value required) (range0, range1)
395  * relation means nothing.
396  *
397  * RETURN VALUE
398  *
399  * TRUE - range is shorter or equal to maximum
400  * FALSE - range is larger than maximum
401  */
403  const SYSTEMTIME *range0,
404  const SYSTEMTIME *range1,
405  SYSTEMTIME *adjust)
406 {
407  ULARGE_INTEGER ul_range0, ul_range1, ul_diff;
408  FILETIME ft_range0, ft_range1;
409  LONG cmp;
410 
411  SystemTimeToFileTime(range0, &ft_range0);
412  SystemTimeToFileTime(range1, &ft_range1);
413 
414  ul_range0.u.LowPart = ft_range0.dwLowDateTime;
415  ul_range0.u.HighPart = ft_range0.dwHighDateTime;
416  ul_range1.u.LowPart = ft_range1.dwLowDateTime;
417  ul_range1.u.HighPart = ft_range1.dwHighDateTime;
418 
419  cmp = CompareFileTime(&ft_range0, &ft_range1);
420 
421  if(cmp == 1)
422  ul_diff.QuadPart = ul_range0.QuadPart - ul_range1.QuadPart;
423  else
424  ul_diff.QuadPart = -ul_range0.QuadPart + ul_range1.QuadPart;
425 
426  if(ul_diff.QuadPart >= DAYSTO100NSECS(infoPtr->maxSelCount)) {
427 
428  if(adjust) {
429  if(cmp == 1)
430  ul_range0.QuadPart = ul_range1.QuadPart + DAYSTO100NSECS(infoPtr->maxSelCount - 1);
431  else
432  ul_range0.QuadPart = ul_range1.QuadPart - DAYSTO100NSECS(infoPtr->maxSelCount - 1);
433 
434  ft_range0.dwLowDateTime = ul_range0.u.LowPart;
435  ft_range0.dwHighDateTime = ul_range0.u.HighPart;
436  FileTimeToSystemTime(&ft_range0, adjust);
437  }
438 
439  return FALSE;
440  }
441  else return TRUE;
442 }
443 
444 /* Used in MCM_SETRANGE/MCM_SETSELRANGE to determine resulting time part.
445  Milliseconds are intentionally not validated. */
447 {
448  if((time->wHour > 24) || (time->wMinute > 59) || (time->wSecond > 59))
449  return FALSE;
450  else
451  return TRUE;
452 }
453 
454 /* Note:Depending on DST, this may be offset by a day.
455  Need to find out if we're on a DST place & adjust the clock accordingly.
456  Above function assumes we have a valid data.
457  Valid for year>1752; 1 <= d <= 31, 1 <= m <= 12.
458  0 = Sunday.
459 */
460 
461 /* Returns the day in the week
462  *
463  * PARAMETERS
464  * [i] date : input date
465  * [I] inplace : set calculated value back to date structure
466  *
467  * RETURN VALUE
468  * day of week in SYSTEMTIME format: (0 == sunday,..., 6 == saturday)
469  */
471 {
472  SYSTEMTIME st = st_null;
473  FILETIME ft;
474 
475  MONTHCAL_CopyDate(date, &st);
476 
477  SystemTimeToFileTime(&st, &ft);
478  FileTimeToSystemTime(&ft, &st);
479 
480  if (inplace) date->wDayOfWeek = st.wDayOfWeek;
481 
482  return st.wDayOfWeek;
483 }
484 
485 /* add/subtract 'months' from date */
486 static inline void MONTHCAL_GetMonth(SYSTEMTIME *date, INT months)
487 {
488  INT length, m = date->wMonth + months;
489 
490  date->wYear += m > 0 ? (m - 1) / 12 : m / 12 - 1;
491  date->wMonth = m > 0 ? (m - 1) % 12 + 1 : 12 + m % 12;
492  /* fix moving from last day in a month */
493  length = MONTHCAL_MonthLength(date->wMonth, date->wYear);
494  if(date->wDay > length) date->wDay = length;
496 }
497 
498 /* properly updates date to point on next month */
500 {
502 }
503 
504 /* properly updates date to point on prev month */
506 {
507  MONTHCAL_GetMonth(date, -1);
508 }
509 
510 /* Returns full date for a first currently visible day */
511 static void MONTHCAL_GetMinDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
512 {
513  /* zero indexed calendar has the earliest date */
514  SYSTEMTIME st_first = infoPtr->calendars[0].month;
515  INT firstDay;
516 
517  st_first.wDay = 1;
518  firstDay = MONTHCAL_CalculateDayOfWeek(&st_first, FALSE);
519 
520  *date = infoPtr->calendars[0].month;
522 
523  date->wDay = MONTHCAL_MonthLength(date->wMonth, date->wYear) +
524  (infoPtr->firstDay - firstDay) % 7 + 1;
525 
526  if(date->wDay > MONTHCAL_MonthLength(date->wMonth, date->wYear))
527  date->wDay -= 7;
528 
529  /* fix day of week */
531 }
532 
533 /* Returns full date for a last currently visible day */
534 static void MONTHCAL_GetMaxDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
535 {
536  /* the latest date is in latest calendar */
537  SYSTEMTIME st, *lt_month = &infoPtr->calendars[MONTHCAL_GetCalCount(infoPtr)-1].month;
538  INT first_day;
539 
540  *date = *lt_month;
541  st = *lt_month;
542 
543  /* day of week of first day of current month */
544  st.wDay = 1;
545  first_day = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
546 
549 
550  /* last calendar starts with some date from previous month that not displayed */
551  st.wDay = MONTHCAL_MonthLength(st.wMonth, st.wYear) +
552  (infoPtr->firstDay - first_day) % 7 + 1;
553  if (st.wDay > MONTHCAL_MonthLength(st.wMonth, st.wYear)) st.wDay -= 7;
554 
555  /* Use month length to get max day. 42 means max day count in calendar area */
556  date->wDay = 42 - (MONTHCAL_MonthLength(st.wMonth, st.wYear) - st.wDay + 1) -
557  MONTHCAL_MonthLength(lt_month->wMonth, lt_month->wYear);
558 
559  /* fix day of week */
561 }
562 
563 /* From a given point calculate the row, column and day in the calendar,
564  'day == 0' means the last day of the last month. */
565 static int MONTHCAL_GetDayFromPos(const MONTHCAL_INFO *infoPtr, POINT pt, INT calIdx)
566 {
567  SYSTEMTIME st = infoPtr->calendars[calIdx].month;
568  int firstDay, col, row;
569  RECT client;
570 
571  GetClientRect(infoPtr->hwndSelf, &client);
572 
573  /* if the point is outside the x bounds of the window put it at the boundary */
574  if (pt.x > client.right) pt.x = client.right;
575 
576  col = (pt.x - infoPtr->calendars[calIdx].days.left ) / infoPtr->width_increment;
577  row = (pt.y - infoPtr->calendars[calIdx].days.top ) / infoPtr->height_increment;
578 
579  st.wDay = 1;
580  firstDay = (MONTHCAL_CalculateDayOfWeek(&st, FALSE) + 6 - infoPtr->firstDay) % 7;
581  return col + 7 * row - firstDay;
582 }
583 
584 /* Get day position for given date and calendar
585  *
586  * PARAMETERS
587  *
588  * [I] infoPtr : pointer to control data
589  * [I] date : date value
590  * [O] col : day column (zero based)
591  * [O] row : week column (zero based)
592  * [I] calIdx : calendar index
593  */
594 static void MONTHCAL_GetDayPos(const MONTHCAL_INFO *infoPtr, const SYSTEMTIME *date,
595  INT *col, INT *row, INT calIdx)
596 {
597  SYSTEMTIME st = infoPtr->calendars[calIdx].month;
598  INT first;
599 
600  st.wDay = 1;
601  first = (MONTHCAL_CalculateDayOfWeek(&st, FALSE) + 6 - infoPtr->firstDay) % 7;
602 
603  if (calIdx == 0 || calIdx == MONTHCAL_GetCalCount(infoPtr)-1) {
604  const SYSTEMTIME *cal = &infoPtr->calendars[calIdx].month;
606 
607  /* previous month */
608  if (cmp == -1) {
609  *col = (first - MONTHCAL_MonthLength(date->wMonth, cal->wYear) + date->wDay) % 7;
610  *row = 0;
611  return;
612  }
613 
614  /* next month calculation is same as for current, just add current month length */
615  if (cmp == 1)
616  first += MONTHCAL_MonthLength(cal->wMonth, cal->wYear);
617  }
618 
619  *col = (date->wDay + first) % 7;
620  *row = (date->wDay + first - *col) / 7;
621 }
622 
623 /* returns bounding box for day in given position in given calendar */
624 static inline void MONTHCAL_GetDayRectI(const MONTHCAL_INFO *infoPtr, RECT *r,
625  INT col, INT row, INT calIdx)
626 {
627  r->left = infoPtr->calendars[calIdx].days.left + col * infoPtr->width_increment;
628  r->right = r->left + infoPtr->width_increment;
629  r->top = infoPtr->calendars[calIdx].days.top + row * infoPtr->height_increment;
630  r->bottom = r->top + infoPtr->textHeight;
631 }
632 
633 /* Returns bounding box for given date
634  *
635  * NOTE: when calendar index is unknown pass -1
636  */
637 static BOOL MONTHCAL_GetDayRect(const MONTHCAL_INFO *infoPtr, const SYSTEMTIME *date, RECT *r, INT calIdx)
638 {
639  INT col, row;
640 
642  {
643  SetRectEmpty(r);
644  return FALSE;
645  }
646 
647  if (calIdx == -1)
648  {
650 
651  if (cmp <= 0)
652  calIdx = 0;
653  else
654  {
656  if (cmp >= 0)
657  calIdx = MONTHCAL_GetCalCount(infoPtr)-1;
658  else
659  {
660  for (calIdx = 1; calIdx < MONTHCAL_GetCalCount(infoPtr)-1; calIdx++)
661  if (MONTHCAL_CompareMonths(date, &infoPtr->calendars[calIdx].month) == 0)
662  break;
663  }
664  }
665  }
666 
667  MONTHCAL_GetDayPos(infoPtr, date, &col, &row, calIdx);
668  MONTHCAL_GetDayRectI(infoPtr, r, col, row, calIdx);
669 
670  return TRUE;
671 }
672 
673 static LRESULT
675 {
676  INT range;
677 
678  TRACE("flag=%d, st=%p\n", flag, st);
679 
680  switch (flag) {
681  case GMR_VISIBLE:
682  {
683  if (st)
684  {
685  st[0] = infoPtr->calendars[0].month;
686  st[1] = infoPtr->calendars[MONTHCAL_GetCalCount(infoPtr)-1].month;
687 
688  if (st[0].wMonth == min_allowed_date.wMonth &&
689  st[0].wYear == min_allowed_date.wYear)
690  {
691  st[0].wDay = min_allowed_date.wDay;
692  }
693  else
694  st[0].wDay = 1;
696 
697  st[1].wDay = MONTHCAL_MonthLength(st[1].wMonth, st[1].wYear);
699  }
700 
701  range = MONTHCAL_GetCalCount(infoPtr);
702  break;
703  }
704  case GMR_DAYSTATE:
705  {
706  if (st)
707  {
708  MONTHCAL_GetMinDate(infoPtr, &st[0]);
709  MONTHCAL_GetMaxDate(infoPtr, &st[1]);
710  }
711  /* include two partially visible months */
712  range = MONTHCAL_GetCalCount(infoPtr) + 2;
713  break;
714  }
715  default:
716  WARN("Unknown flag value, got %d\n", flag);
717  range = 0;
718  }
719 
720  return range;
721 }
722 
723 /* Focused day helper:
724 
725  - set focused date to given value;
726  - reset to zero value if NULL passed;
727  - invalidate previous and new day rectangle only if needed.
728 
729  Returns TRUE if focused day changed, FALSE otherwise.
730 */
732 {
733  RECT r;
734 
735  if(st)
736  {
737  /* there's nothing to do if it's the same date,
738  mouse move within same date rectangle case */
739  if(MONTHCAL_IsDateEqual(&infoPtr->focusedSel, st)) return FALSE;
740 
741  /* invalidate old focused day */
742  if (MONTHCAL_GetDayRect(infoPtr, &infoPtr->focusedSel, &r, -1))
743  InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
744 
745  infoPtr->focusedSel = *st;
746  }
747 
748  /* On set invalidates new day, on reset clears previous focused day. */
749  if (MONTHCAL_GetDayRect(infoPtr, &infoPtr->focusedSel, &r, -1))
750  InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
751 
752  if(!st && MONTHCAL_ValidateDate(&infoPtr->focusedSel))
753  infoPtr->focusedSel = st_null;
754 
755  return TRUE;
756 }
757 
758 /* draw today boundary box for specified rectangle */
759 static void MONTHCAL_Circle(const MONTHCAL_INFO *infoPtr, HDC hdc, const RECT *r)
760 {
761  HPEN old_pen = SelectObject(hdc, infoPtr->pens[PenRed]);
762  HBRUSH old_brush;
763 
764  old_brush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
765  Rectangle(hdc, r->left, r->top, r->right, r->bottom);
766 
767  SelectObject(hdc, old_brush);
768  SelectObject(hdc, old_pen);
769 }
770 
771 /* Draw today day mark rectangle
772  *
773  * [I] hdc : context to draw in
774  * [I] date : day to mark with rectangle
775  *
776  */
777 static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc,
778  const SYSTEMTIME *date)
779 {
780  RECT r;
781 
782  MONTHCAL_GetDayRect(infoPtr, date, &r, -1);
783  MONTHCAL_Circle(infoPtr, hdc, &r);
784 }
785 
786 static void MONTHCAL_DrawDay(const MONTHCAL_INFO *infoPtr, HDC hdc, const SYSTEMTIME *st,
787  int bold, const PAINTSTRUCT *ps)
788 {
789  static const WCHAR fmtW[] = { '%','d',0 };
790  WCHAR buf[10];
791  RECT r, r_temp;
792  COLORREF oldCol = 0;
793  COLORREF oldBk = 0;
794  INT old_bkmode, selection;
795 
796  /* no need to check styles: when selection is not valid, it is set to zero.
797  1 < day < 31, so everything is OK */
798  MONTHCAL_GetDayRect(infoPtr, st, &r, -1);
799  if(!IntersectRect(&r_temp, &(ps->rcPaint), &r)) return;
800 
801  if ((MONTHCAL_CompareDate(st, &infoPtr->minSel) >= 0) &&
802  (MONTHCAL_CompareDate(st, &infoPtr->maxSel) <= 0))
803  {
804  TRACE("%d %d %d\n", st->wDay, infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
805  TRACE("%s\n", wine_dbgstr_rect(&r));
806  oldCol = SetTextColor(hdc, infoPtr->colors[MCSC_MONTHBK]);
807  oldBk = SetBkColor(hdc, infoPtr->colors[MCSC_TRAILINGTEXT]);
808  FillRect(hdc, &r, infoPtr->brushes[BrushTitle]);
809 
810  selection = 1;
811  }
812  else
813  selection = 0;
814 
815  SelectObject(hdc, bold ? infoPtr->hBoldFont : infoPtr->hFont);
816 
817  old_bkmode = SetBkMode(hdc, TRANSPARENT);
818  wsprintfW(buf, fmtW, st->wDay);
820  SetBkMode(hdc, old_bkmode);
821 
822  if (selection)
823  {
824  SetTextColor(hdc, oldCol);
825  SetBkColor(hdc, oldBk);
826  }
827 }
828 
830 {
831  HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
832  RECT *r = button == DIRECTION_FORWARD ? &infoPtr->titlebtnnext : &infoPtr->titlebtnprev;
833  BOOL pressed = button == DIRECTION_FORWARD ? infoPtr->status & MC_NEXTPRESSED :
834  infoPtr->status & MC_PREVPRESSED;
835  if (theme)
836  {
837  static const int states[] = {
838  /* Prev button */
840  /* Next button */
842  };
843  int stateNum = button == DIRECTION_FORWARD ? 3 : 0;
844  if (pressed)
845  stateNum += 1;
846  else
847  {
848  if (infoPtr->dwStyle & WS_DISABLED) stateNum += 2;
849  }
850  DrawThemeBackground (theme, hdc, SBP_ARROWBTN, states[stateNum], r, NULL);
851  }
852  else
853  {
855  if (pressed)
856  style |= DFCS_PUSHED;
857  else
858  {
859  if (infoPtr->dwStyle & WS_DISABLED) style |= DFCS_INACTIVE;
860  }
861 
863  }
864 }
865 
866 /* paint a title with buttons and month/year string */
867 static void MONTHCAL_PaintTitle(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
868 {
869  static const WCHAR mmmmW[] = {'M','M','M','M',0};
870  static const WCHAR mmmW[] = {'M','M','M',0};
871  static const WCHAR mmW[] = {'M','M',0};
872  static const WCHAR fmtyearW[] = {'%','l','d',0};
873  static const WCHAR fmtmmW[] = {'%','0','2','d',0};
874  static const WCHAR fmtmW[] = {'%','d',0};
875  RECT *title = &infoPtr->calendars[calIdx].title;
876  const SYSTEMTIME *st = &infoPtr->calendars[calIdx].month;
877  WCHAR monthW[80], strW[80], fmtW[80], yearW[6] /* valid year range is 1601-30827 */;
878  int yearoffset, monthoffset, shiftX;
879  SIZE sz;
880 
881  /* fill header box */
882  FillRect(hdc, title, infoPtr->brushes[BrushTitle]);
883 
884  /* month/year string */
885  SetBkColor(hdc, infoPtr->colors[MCSC_TITLEBK]);
887  SelectObject(hdc, infoPtr->hBoldFont);
888 
889  /* draw formatted date string */
890  GetDateFormatW(LOCALE_USER_DEFAULT, DATE_YEARMONTH, st, NULL, strW, ARRAY_SIZE(strW));
892 
893  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SYEARMONTH, fmtW, ARRAY_SIZE(fmtW));
894  wsprintfW(yearW, fmtyearW, st->wYear);
895 
896  /* month is trickier as it's possible to have different format pictures, we'll
897  test for M, MM, MMM, and MMMM */
898  if (strstrW(fmtW, mmmmW))
900  else if (strstrW(fmtW, mmmW))
902  else if (strstrW(fmtW, mmW))
903  wsprintfW(monthW, fmtmmW, st->wMonth);
904  else
905  wsprintfW(monthW, fmtmW, st->wMonth);
906 
907  /* update hit boxes */
908  yearoffset = 0;
909  while (strW[yearoffset])
910  {
911  if (!strncmpW(&strW[yearoffset], yearW, strlenW(yearW)))
912  break;
913  yearoffset++;
914  }
915 
916  monthoffset = 0;
917  while (strW[monthoffset])
918  {
919  if (!strncmpW(&strW[monthoffset], monthW, strlenW(monthW)))
920  break;
921  monthoffset++;
922  }
923 
924  /* for left limits use offsets */
925  sz.cx = 0;
926  if (yearoffset)
927  GetTextExtentPoint32W(hdc, strW, yearoffset, &sz);
928  infoPtr->calendars[calIdx].titleyear.left = sz.cx;
929 
930  sz.cx = 0;
931  if (monthoffset)
932  GetTextExtentPoint32W(hdc, strW, monthoffset, &sz);
933  infoPtr->calendars[calIdx].titlemonth.left = sz.cx;
934 
935  /* for right limits use actual string parts lengths */
936  GetTextExtentPoint32W(hdc, &strW[yearoffset], strlenW(yearW), &sz);
937  infoPtr->calendars[calIdx].titleyear.right = infoPtr->calendars[calIdx].titleyear.left + sz.cx;
938 
939  GetTextExtentPoint32W(hdc, monthW, strlenW(monthW), &sz);
940  infoPtr->calendars[calIdx].titlemonth.right = infoPtr->calendars[calIdx].titlemonth.left + sz.cx;
941 
942  /* Finally translate rectangles to match center aligned string,
943  hit rectangles are relative to title rectangle before translation. */
945  shiftX = (title->right - title->left - sz.cx) / 2 + title->left;
946  OffsetRect(&infoPtr->calendars[calIdx].titleyear, shiftX, 0);
947  OffsetRect(&infoPtr->calendars[calIdx].titlemonth, shiftX, 0);
948 }
949 
950 static void MONTHCAL_PaintWeeknumbers(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
951 {
952  const SYSTEMTIME *date = &infoPtr->calendars[calIdx].month;
953  static const WCHAR fmt_weekW[] = { '%','d',0 };
954  INT mindays, weeknum, weeknum1, startofprescal;
955  INT i, prev_month;
956  SYSTEMTIME st;
957  WCHAR buf[80];
958  HPEN old_pen;
959  RECT r;
960 
961  if (!(infoPtr->dwStyle & MCS_WEEKNUMBERS)) return;
962 
963  MONTHCAL_GetMinDate(infoPtr, &st);
964  startofprescal = st.wDay;
965  st = *date;
966 
967  prev_month = date->wMonth - 1;
968  if(prev_month == 0) prev_month = 12;
969 
970  /*
971  Rules what week to call the first week of a new year:
972  LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?):
973  The week containing Jan 1 is the first week of year
974  LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany):
975  First week of year must contain 4 days of the new year
976  LOCALE_IFIRSTWEEKOFYEAR == 1 (what countries?)
977  The first week of the year must contain only days of the new year
978  */
980  weeknum = atoiW(buf);
981  switch (weeknum)
982  {
983  case 1: mindays = 6;
984  break;
985  case 2: mindays = 3;
986  break;
987  case 0: mindays = 0;
988  break;
989  default:
990  WARN("Unknown LOCALE_IFIRSTWEEKOFYEAR value %d, defaulting to 0\n", weeknum);
991  mindays = 0;
992  }
993 
994  if (date->wMonth == 1)
995  {
996  /* calculate all those exceptions for January */
997  st.wDay = st.wMonth = 1;
998  weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
999  if ((infoPtr->firstDay - weeknum1) % 7 > mindays)
1000  weeknum = 1;
1001  else
1002  {
1003  weeknum = 0;
1004  for(i = 0; i < 11; i++)
1005  weeknum += MONTHCAL_MonthLength(i+1, date->wYear - 1);
1006 
1007  weeknum += startofprescal + 7;
1008  weeknum /= 7;
1009  st.wYear -= 1;
1010  weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
1011  if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
1012  }
1013  }
1014  else
1015  {
1016  weeknum = 0;
1017  for(i = 0; i < prev_month - 1; i++)
1018  weeknum += MONTHCAL_MonthLength(i+1, date->wYear);
1019 
1020  weeknum += startofprescal + 7;
1021  weeknum /= 7;
1022  st.wDay = st.wMonth = 1;
1023  weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
1024  if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
1025  }
1026 
1027  r = infoPtr->calendars[calIdx].weeknums;
1028 
1029  /* erase whole week numbers area */
1030  FillRect(hdc, &r, infoPtr->brushes[BrushMonth]);
1031  SetTextColor(hdc, infoPtr->colors[MCSC_TITLEBK]);
1032 
1033  /* reduce rectangle to one week number */
1034  r.bottom = r.top + infoPtr->height_increment;
1035 
1036  for(i = 0; i < 6; i++) {
1037  if((i == 0) && (weeknum > 50))
1038  {
1039  wsprintfW(buf, fmt_weekW, weeknum);
1040  weeknum = 0;
1041  }
1042  else if((i == 5) && (weeknum > 47))
1043  {
1044  wsprintfW(buf, fmt_weekW, 1);
1045  }
1046  else
1047  wsprintfW(buf, fmt_weekW, weeknum + i);
1048 
1050  OffsetRect(&r, 0, infoPtr->height_increment);
1051  }
1052 
1053  /* line separator for week numbers column */
1054  old_pen = SelectObject(hdc, infoPtr->pens[PenText]);
1055  MoveToEx(hdc, infoPtr->calendars[calIdx].weeknums.right, infoPtr->calendars[calIdx].weeknums.top + 3 , NULL);
1056  LineTo(hdc, infoPtr->calendars[calIdx].weeknums.right, infoPtr->calendars[calIdx].weeknums.bottom);
1057  SelectObject(hdc, old_pen);
1058 }
1059 
1060 /* bottom today date */
1061 static void MONTHCAL_PaintTodayTitle(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
1062 {
1063  static const WCHAR fmt_todayW[] = { '%','s',' ','%','s',0 };
1064  WCHAR buf_todayW[30], buf_dateW[20], buf[80];
1065  RECT text_rect, box_rect;
1066  HFONT old_font;
1067  INT col;
1068 
1069  if(infoPtr->dwStyle & MCS_NOTODAY) return;
1070 
1071  LoadStringW(COMCTL32_hModule, IDM_TODAY, buf_todayW, ARRAY_SIZE(buf_todayW));
1072  col = infoPtr->dwStyle & MCS_NOTODAYCIRCLE ? 0 : 1;
1073  if (infoPtr->dwStyle & MCS_WEEKNUMBERS) col--;
1074  /* label is located below first calendar last row */
1075  MONTHCAL_GetDayRectI(infoPtr, &text_rect, col, 6, infoPtr->dim.cx * infoPtr->dim.cy - infoPtr->dim.cx);
1076  box_rect = text_rect;
1077 
1078  GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &infoPtr->todaysDate, NULL, buf_dateW, ARRAY_SIZE(buf_dateW));
1079  old_font = SelectObject(hdc, infoPtr->hBoldFont);
1080  SetTextColor(hdc, infoPtr->colors[MCSC_TEXT]);
1081 
1082  wsprintfW(buf, fmt_todayW, buf_todayW, buf_dateW);
1085 
1086  if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE)) {
1087  OffsetRect(&box_rect, -infoPtr->width_increment, 0);
1088  MONTHCAL_Circle(infoPtr, hdc, &box_rect);
1089  }
1090 
1091  SelectObject(hdc, old_font);
1092 }
1093 
1094 /* today mark + focus */
1095 static void MONTHCAL_PaintFocusAndCircle(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
1096 {
1097  /* circle today date if only it's in fully visible month */
1098  if (!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
1099  {
1100  INT i;
1101 
1102  for (i = 0; i < MONTHCAL_GetCalCount(infoPtr); i++)
1103  if (!MONTHCAL_CompareMonths(&infoPtr->todaysDate, &infoPtr->calendars[i].month))
1104  {
1105  MONTHCAL_CircleDay(infoPtr, hdc, &infoPtr->todaysDate);
1106  break;
1107  }
1108  }
1109 
1110  if (!MONTHCAL_IsDateEqual(&infoPtr->focusedSel, &st_null))
1111  {
1112  RECT r;
1113  MONTHCAL_GetDayRect(infoPtr, &infoPtr->focusedSel, &r, -1);
1114  DrawFocusRect(hdc, &r);
1115  }
1116 }
1117 
1118 /* months before first calendar month and after last calendar month */
1119 static void MONTHCAL_PaintLeadTrailMonths(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
1120 {
1121  INT mask, index;
1122  UINT length;
1123  SYSTEMTIME st_max, st;
1124 
1125  if (infoPtr->dwStyle & MCS_NOTRAILINGDATES) return;
1126 
1128 
1129  /* draw prev month */
1130  MONTHCAL_GetMinDate(infoPtr, &st);
1131  mask = 1 << (st.wDay-1);
1132  /* December and January both 31 days long, so no worries if wrapped */
1133  length = MONTHCAL_MonthLength(infoPtr->calendars[0].month.wMonth - 1,
1134  infoPtr->calendars[0].month.wYear);
1135  index = 0;
1136  while(st.wDay <= length)
1137  {
1138  MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[index] & mask, ps);
1139  mask <<= 1;
1140  st.wDay++;
1141  }
1142 
1143  /* draw next month */
1144  st = infoPtr->calendars[MONTHCAL_GetCalCount(infoPtr)-1].month;
1145  st.wDay = 1;
1146  MONTHCAL_GetNextMonth(&st);
1147  MONTHCAL_GetMaxDate(infoPtr, &st_max);
1148  mask = 1;
1149  index = MONTHCAL_GetMonthRange(infoPtr, GMR_DAYSTATE, 0)-1;
1150  while(st.wDay <= st_max.wDay)
1151  {
1152  MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[index] & mask, ps);
1153  mask <<= 1;
1154  st.wDay++;
1155  }
1156 }
1157 
1158 static int get_localized_dayname(const MONTHCAL_INFO *infoPtr, unsigned int day, WCHAR *buff, unsigned int count)
1159 {
1160  LCTYPE lctype;
1161 
1162  if (infoPtr->dwStyle & MCS_SHORTDAYSOFWEEK)
1163  lctype = LOCALE_SSHORTESTDAYNAME1 + day;
1164  else
1165  lctype = LOCALE_SABBREVDAYNAME1 + day;
1166 
1167  return GetLocaleInfoW(LOCALE_USER_DEFAULT, lctype, buff, count);
1168 }
1169 
1170 /* paint a calendar area */
1171 static void MONTHCAL_PaintCalendar(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
1172 {
1173  const SYSTEMTIME *date = &infoPtr->calendars[calIdx].month;
1174  INT i, j;
1175  UINT length;
1176  RECT r, fill_bk_rect;
1177  SYSTEMTIME st;
1178  WCHAR buf[80];
1179  HPEN old_pen;
1180  int mask;
1181 
1182  /* fill whole days area - from week days area to today note rectangle */
1183  fill_bk_rect = infoPtr->calendars[calIdx].wdays;
1184  fill_bk_rect.bottom = infoPtr->calendars[calIdx].days.bottom +
1185  (infoPtr->todayrect.bottom - infoPtr->todayrect.top);
1186 
1187  FillRect(hdc, &fill_bk_rect, infoPtr->brushes[BrushMonth]);
1188 
1189  /* draw line under day abbreviations */
1190  old_pen = SelectObject(hdc, infoPtr->pens[PenText]);
1191  MoveToEx(hdc, infoPtr->calendars[calIdx].days.left + 3,
1192  infoPtr->calendars[calIdx].title.bottom + infoPtr->textHeight + 1, NULL);
1193  LineTo(hdc, infoPtr->calendars[calIdx].days.right - 3,
1194  infoPtr->calendars[calIdx].title.bottom + infoPtr->textHeight + 1);
1195  SelectObject(hdc, old_pen);
1196 
1197  infoPtr->calendars[calIdx].wdays.left = infoPtr->calendars[calIdx].days.left =
1198  infoPtr->calendars[calIdx].weeknums.right;
1199 
1200  /* draw day abbreviations */
1201  SelectObject(hdc, infoPtr->hFont);
1202  SetBkColor(hdc, infoPtr->colors[MCSC_MONTHBK]);
1203  SetTextColor(hdc, infoPtr->colors[MCSC_TITLEBK]);
1204  /* rectangle to draw a single day abbreviation within */
1205  r = infoPtr->calendars[calIdx].wdays;
1206  r.right = r.left + infoPtr->width_increment;
1207 
1208  i = infoPtr->firstDay;
1209  for(j = 0; j < 7; j++) {
1210  get_localized_dayname(infoPtr, (i + j + 6) % 7, buf, ARRAY_SIZE(buf));
1212  OffsetRect(&r, infoPtr->width_increment, 0);
1213  }
1214 
1215  /* draw current month */
1216  SetTextColor(hdc, infoPtr->colors[MCSC_TEXT]);
1217  st = *date;
1218  st.wDay = 1;
1219  mask = 1;
1220  length = MONTHCAL_MonthLength(date->wMonth, date->wYear);
1221  while(st.wDay <= length)
1222  {
1223  MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[calIdx+1] & mask, ps);
1224  mask <<= 1;
1225  st.wDay++;
1226  }
1227 }
1228 
1229 static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
1230 {
1231  COLORREF old_text_clr, old_bk_clr;
1232  HFONT old_font;
1233  INT i;
1234 
1235  old_text_clr = SetTextColor(hdc, comctl32_color.clrWindowText);
1236  old_bk_clr = GetBkColor(hdc);
1237  old_font = GetCurrentObject(hdc, OBJ_FONT);
1238 
1239  for (i = 0; i < MONTHCAL_GetCalCount(infoPtr); i++)
1240  {
1241  RECT *title = &infoPtr->calendars[i].title;
1242  RECT r;
1243 
1244  /* draw title, redraw all its elements */
1245  if (IntersectRect(&r, &(ps->rcPaint), title))
1246  MONTHCAL_PaintTitle(infoPtr, hdc, ps, i);
1247 
1248  /* draw calendar area */
1249  UnionRect(&r, &infoPtr->calendars[i].wdays, &infoPtr->todayrect);
1250  if (IntersectRect(&r, &(ps->rcPaint), &r))
1251  MONTHCAL_PaintCalendar(infoPtr, hdc, ps, i);
1252 
1253  /* week numbers */
1254  MONTHCAL_PaintWeeknumbers(infoPtr, hdc, ps, i);
1255  }
1256 
1257  /* partially visible months */
1258  MONTHCAL_PaintLeadTrailMonths(infoPtr, hdc, ps);
1259 
1260  /* focus and today rectangle */
1261  MONTHCAL_PaintFocusAndCircle(infoPtr, hdc, ps);
1262 
1263  /* today at the bottom left */
1264  MONTHCAL_PaintTodayTitle(infoPtr, hdc, ps);
1265 
1266  /* navigation buttons */
1269 
1270  /* restore context */
1271  SetBkColor(hdc, old_bk_clr);
1272  SelectObject(hdc, old_font);
1273  SetTextColor(hdc, old_text_clr);
1274 }
1275 
1276 static LRESULT
1278 {
1279  TRACE("rect %p\n", rect);
1280 
1281  if(!rect) return FALSE;
1282 
1283  *rect = infoPtr->calendars[0].title;
1284  rect->bottom = infoPtr->calendars[0].days.bottom + infoPtr->todayrect.bottom -
1285  infoPtr->todayrect.top;
1286 
1287  AdjustWindowRect(rect, infoPtr->dwStyle, FALSE);
1288 
1289  /* minimal rectangle is zero based */
1290  OffsetRect(rect, -rect->left, -rect->top);
1291 
1292  TRACE("%s\n", wine_dbgstr_rect(rect));
1293 
1294  return TRUE;
1295 }
1296 
1297 static COLORREF
1299 {
1300  TRACE("%p, %d\n", infoPtr, index);
1301 
1302  if (index > MCSC_TRAILINGTEXT) return -1;
1303  return infoPtr->colors[index];
1304 }
1305 
1306 static LRESULT
1308 {
1309  enum CachedBrush type;
1310  COLORREF prev;
1311 
1312  TRACE("%p, %d: color %08x\n", infoPtr, index, color);
1313 
1314  if (index > MCSC_TRAILINGTEXT) return -1;
1315 
1316  prev = infoPtr->colors[index];
1317  infoPtr->colors[index] = color;
1318 
1319  /* update cached brush */
1320  switch (index)
1321  {
1322  case MCSC_BACKGROUND:
1324  break;
1325  case MCSC_TITLEBK:
1326  type = BrushTitle;
1327  break;
1328  case MCSC_MONTHBK:
1329  type = BrushMonth;
1330  break;
1331  default:
1332  type = BrushLast;
1333  }
1334 
1335  if (type != BrushLast)
1336  {
1337  DeleteObject(infoPtr->brushes[type]);
1338  infoPtr->brushes[type] = CreateSolidBrush(color);
1339  }
1340 
1341  /* update cached pen */
1342  if (index == MCSC_TEXT)
1343  {
1344  DeleteObject(infoPtr->pens[PenText]);
1345  infoPtr->pens[PenText] = CreatePen(PS_SOLID, 1, infoPtr->colors[index]);
1346  }
1347 
1349  return prev;
1350 }
1351 
1352 static LRESULT
1354 {
1355  TRACE("\n");
1356 
1357  if(infoPtr->delta)
1358  return infoPtr->delta;
1359 
1360  return MONTHCAL_GetMonthRange(infoPtr, GMR_VISIBLE, NULL);
1361 }
1362 
1363 
1364 static LRESULT
1366 {
1367  INT prev = infoPtr->delta;
1368 
1369  TRACE("delta %d\n", delta);
1370 
1371  infoPtr->delta = delta;
1372  return prev;
1373 }
1374 
1375 
1376 static inline LRESULT
1378 {
1379  int day;
1380 
1381  /* convert from SYSTEMTIME to locale format */
1382  day = (infoPtr->firstDay >= 0) ? (infoPtr->firstDay+6)%7 : infoPtr->firstDay;
1383 
1384  return MAKELONG(day, infoPtr->firstDaySet);
1385 }
1386 
1387 
1388 /* Sets the first day of the week that will appear in the control
1389  *
1390  *
1391  * PARAMETERS:
1392  * [I] infoPtr : valid pointer to control data
1393  * [I] day : day number to set as new first day (0 == Monday,...,6 == Sunday)
1394  *
1395  *
1396  * RETURN VALUE:
1397  * Low word contains previous first day,
1398  * high word indicates was first day forced with this message before or is
1399  * locale defined (TRUE - was forced, FALSE - wasn't).
1400  *
1401  * FIXME: this needs to be implemented properly in MONTHCAL_Refresh()
1402  * FIXME: we need more error checking here
1403  */
1404 static LRESULT
1406 {
1407  LRESULT prev = MONTHCAL_GetFirstDayOfWeek(infoPtr);
1408  int new_day;
1409 
1410  TRACE("%d\n", day);
1411 
1412  if(day == -1)
1413  {
1414  WCHAR buf[80];
1415 
1417  TRACE("%s %d\n", debugstr_w(buf), strlenW(buf));
1418 
1419  new_day = atoiW(buf);
1420 
1421  infoPtr->firstDaySet = FALSE;
1422  }
1423  else if(day >= 7)
1424  {
1425  new_day = 6; /* max first day allowed */
1426  infoPtr->firstDaySet = TRUE;
1427  }
1428  else
1429  {
1430  /* Native behaviour for that case is broken: invalid date number >31
1431  got displayed at (0,0) position, current month starts always from
1432  (1,0) position. Should be implemented here as well only if there's
1433  nothing else to do. */
1434  if (day < -1)
1435  FIXME("No bug compatibility for day=%d\n", day);
1436 
1437  new_day = day;
1438  infoPtr->firstDaySet = TRUE;
1439  }
1440 
1441  /* convert from locale to SYSTEMTIME format */
1442  infoPtr->firstDay = (new_day >= 0) ? (++new_day) % 7 : new_day;
1443 
1444  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
1445 
1446  return prev;
1447 }
1448 
1449 static LRESULT
1451 {
1452  return(infoPtr->todayrect.right - infoPtr->todayrect.left);
1453 }
1454 
1455 static LRESULT
1457 {
1458  FILETIME ft_min, ft_max;
1459 
1460  TRACE("%x %p\n", limits, range);
1461 
1462  if ((limits & GDTR_MIN && !MONTHCAL_ValidateDate(&range[0])) ||
1463  (limits & GDTR_MAX && !MONTHCAL_ValidateDate(&range[1])))
1464  return FALSE;
1465 
1466  infoPtr->rangeValid = 0;
1467  infoPtr->minDate = infoPtr->maxDate = st_null;
1468 
1469  if (limits & GDTR_MIN)
1470  {
1471  if (!MONTHCAL_ValidateTime(&range[0]))
1472  MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[0]);
1473 
1474  infoPtr->minDate = range[0];
1475  infoPtr->rangeValid |= GDTR_MIN;
1476  }
1477  if (limits & GDTR_MAX)
1478  {
1479  if (!MONTHCAL_ValidateTime(&range[1]))
1480  MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[1]);
1481 
1482  infoPtr->maxDate = range[1];
1483  infoPtr->rangeValid |= GDTR_MAX;
1484  }
1485 
1486  /* Only one limit set - we are done */
1487  if ((infoPtr->rangeValid & (GDTR_MIN | GDTR_MAX)) != (GDTR_MIN | GDTR_MAX))
1488  return TRUE;
1489 
1490  SystemTimeToFileTime(&infoPtr->maxDate, &ft_max);
1491  SystemTimeToFileTime(&infoPtr->minDate, &ft_min);
1492 
1493  if (CompareFileTime(&ft_min, &ft_max) >= 0)
1494  {
1495  if ((limits & (GDTR_MIN | GDTR_MAX)) == (GDTR_MIN | GDTR_MAX))
1496  {
1497  /* Native swaps limits only when both limits are being set. */
1498  SYSTEMTIME st_tmp = infoPtr->minDate;
1499  infoPtr->minDate = infoPtr->maxDate;
1500  infoPtr->maxDate = st_tmp;
1501  }
1502  else
1503  {
1504  /* reset the other limit */
1505  if (limits & GDTR_MIN) infoPtr->maxDate = st_null;
1506  if (limits & GDTR_MAX) infoPtr->minDate = st_null;
1507  infoPtr->rangeValid &= limits & GDTR_MIN ? ~GDTR_MAX : ~GDTR_MIN;
1508  }
1509  }
1510 
1511  return TRUE;
1512 }
1513 
1514 
1515 static LRESULT
1517 {
1518  TRACE("%p\n", range);
1519 
1520  if (!range) return 0;
1521 
1522  range[1] = infoPtr->maxDate;
1523  range[0] = infoPtr->minDate;
1524 
1525  return infoPtr->rangeValid;
1526 }
1527 
1528 
1529 static LRESULT
1530 MONTHCAL_SetDayState(const MONTHCAL_INFO *infoPtr, INT months, MONTHDAYSTATE *states)
1531 {
1532  TRACE("%p %d %p\n", infoPtr, months, states);
1533 
1534  if (!(infoPtr->dwStyle & MCS_DAYSTATE)) return 0;
1535  if (months != MONTHCAL_GetMonthRange(infoPtr, GMR_DAYSTATE, 0)) return 0;
1536 
1537  memcpy(infoPtr->monthdayState, states, months*sizeof(MONTHDAYSTATE));
1538 
1539  return 1;
1540 }
1541 
1542 static LRESULT
1544 {
1545  TRACE("%p\n", curSel);
1546  if(!curSel) return FALSE;
1547  if(infoPtr->dwStyle & MCS_MULTISELECT) return FALSE;
1548 
1549  *curSel = infoPtr->minSel;
1550  TRACE("%d/%d/%d\n", curSel->wYear, curSel->wMonth, curSel->wDay);
1551  return TRUE;
1552 }
1553 
1554 static LRESULT
1556 {
1557  SYSTEMTIME prev = infoPtr->minSel, selection;
1558  INT diff;
1559  WORD day;
1560 
1561  TRACE("%p\n", curSel);
1562  if(!curSel) return FALSE;
1563  if(infoPtr->dwStyle & MCS_MULTISELECT) return FALSE;
1564 
1565  if(!MONTHCAL_ValidateDate(curSel)) return FALSE;
1566  /* exit earlier if selection equals current */
1567  if (MONTHCAL_IsDateEqual(&infoPtr->minSel, curSel)) return TRUE;
1568 
1569  selection = *curSel;
1570  selection.wHour = selection.wMinute = selection.wSecond = selection.wMilliseconds = 0;
1572 
1573  if(!MONTHCAL_IsDateInValidRange(infoPtr, &selection, FALSE)) return FALSE;
1574 
1575  /* scroll calendars only if we have to */
1576  diff = MONTHCAL_MonthDiff(&infoPtr->calendars[MONTHCAL_GetCalCount(infoPtr)-1].month, curSel);
1577  if (diff <= 0)
1578  {
1579  diff = MONTHCAL_MonthDiff(&infoPtr->calendars[0].month, curSel);
1580  if (diff > 0) diff = 0;
1581  }
1582 
1583  if (diff != 0)
1584  {
1585  INT i;
1586 
1587  for (i = 0; i < MONTHCAL_GetCalCount(infoPtr); i++)
1588  MONTHCAL_GetMonth(&infoPtr->calendars[i].month, diff);
1589  }
1590 
1591  /* we need to store time part as it is */
1592  selection = *curSel;
1594  infoPtr->minSel = infoPtr->maxSel = selection;
1595 
1596  /* if selection is still in current month, reduce rectangle */
1597  day = prev.wDay;
1598  prev.wDay = curSel->wDay;
1599  if (MONTHCAL_IsDateEqual(&prev, curSel))
1600  {
1601  RECT r_prev, r_new;
1602 
1603  prev.wDay = day;
1604  MONTHCAL_GetDayRect(infoPtr, &prev, &r_prev, -1);
1605  MONTHCAL_GetDayRect(infoPtr, curSel, &r_new, -1);
1606 
1607  InvalidateRect(infoPtr->hwndSelf, &r_prev, FALSE);
1608  InvalidateRect(infoPtr->hwndSelf, &r_new, FALSE);
1609  }
1610  else
1611  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
1612 
1613  return TRUE;
1614 }
1615 
1616 
1617 static LRESULT
1619 {
1620  return infoPtr->maxSelCount;
1621 }
1622 
1623 
1624 static LRESULT
1626 {
1627  TRACE("%d\n", max);
1628 
1629  if(!(infoPtr->dwStyle & MCS_MULTISELECT)) return FALSE;
1630  if(max <= 0) return FALSE;
1631 
1632  infoPtr->maxSelCount = max;
1633 
1634  return TRUE;
1635 }
1636 
1637 
1638 static LRESULT
1640 {
1641  TRACE("%p\n", range);
1642 
1643  if(!range) return FALSE;
1644 
1645  if(infoPtr->dwStyle & MCS_MULTISELECT)
1646  {
1647  range[1] = infoPtr->maxSel;
1648  range[0] = infoPtr->minSel;
1649  TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
1650  return TRUE;
1651  }
1652 
1653  return FALSE;
1654 }
1655 
1656 
1657 static LRESULT
1659 {
1660  SYSTEMTIME old_range[2];
1661  INT diff;
1662 
1663  TRACE("%p\n", range);
1664 
1665  if(!range || !(infoPtr->dwStyle & MCS_MULTISELECT)) return FALSE;
1666 
1667  /* adjust timestamps */
1668  if(!MONTHCAL_ValidateTime(&range[0])) MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[0]);
1669  if(!MONTHCAL_ValidateTime(&range[1])) MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[1]);
1670 
1671  /* maximum range exceeded */
1672  if(!MONTHCAL_IsSelRangeValid(infoPtr, &range[0], &range[1], NULL)) return FALSE;
1673 
1674  old_range[0] = infoPtr->minSel;
1675  old_range[1] = infoPtr->maxSel;
1676 
1677  /* swap if min > max */
1678  if(MONTHCAL_CompareSystemTime(&range[0], &range[1]) <= 0)
1679  {
1680  infoPtr->minSel = range[0];
1681  infoPtr->maxSel = range[1];
1682  }
1683  else
1684  {
1685  infoPtr->minSel = range[1];
1686  infoPtr->maxSel = range[0];
1687  }
1688 
1689  diff = MONTHCAL_MonthDiff(&infoPtr->calendars[MONTHCAL_GetCalCount(infoPtr)-1].month, &infoPtr->maxSel);
1690  if (diff < 0)
1691  {
1692  diff = MONTHCAL_MonthDiff(&infoPtr->calendars[0].month, &infoPtr->maxSel);
1693  if (diff > 0) diff = 0;
1694  }
1695 
1696  if (diff != 0)
1697  {
1698  INT i;
1699 
1700  for (i = 0; i < MONTHCAL_GetCalCount(infoPtr); i++)
1701  MONTHCAL_GetMonth(&infoPtr->calendars[i].month, diff);
1702  }
1703 
1704  /* update day of week */
1707 
1708  /* redraw if bounds changed */
1709  /* FIXME: no actual need to redraw everything */
1710  if(!MONTHCAL_IsDateEqual(&old_range[0], &range[0]) ||
1711  !MONTHCAL_IsDateEqual(&old_range[1], &range[1]))
1712  {
1713  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
1714  }
1715 
1716  TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
1717  return TRUE;
1718 }
1719 
1720 
1721 static LRESULT
1723 {
1724  TRACE("%p\n", today);
1725 
1726  if(!today) return FALSE;
1727  *today = infoPtr->todaysDate;
1728  return TRUE;
1729 }
1730 
1731 /* Internal helper for MCM_SETTODAY handler and auto update timer handler
1732  *
1733  * RETURN VALUE
1734  *
1735  * TRUE - today date changed
1736  * FALSE - today date isn't changed
1737  */
1738 static BOOL
1740 {
1741  RECT rect;
1742 
1743  if (MONTHCAL_IsDateEqual(today, &infoPtr->todaysDate))
1744  return FALSE;
1745 
1746  /* Invalidate old and new today day rectangle, and today label. */
1747  if (MONTHCAL_GetDayRect(infoPtr, &infoPtr->todaysDate, &rect, -1))
1748  InvalidateRect(infoPtr->hwndSelf, &rect, FALSE);
1749 
1750  if (MONTHCAL_GetDayRect(infoPtr, today, &rect, -1))
1751  InvalidateRect(infoPtr->hwndSelf, &rect, FALSE);
1752 
1753  infoPtr->todaysDate = *today;
1754 
1755  InvalidateRect(infoPtr->hwndSelf, &infoPtr->todayrect, FALSE);
1756  return TRUE;
1757 }
1758 
1759 /* MCM_SETTODAT handler */
1760 static LRESULT
1762 {
1763  TRACE("%p\n", today);
1764 
1765  if (today)
1766  {
1767  /* remember if date was set successfully */
1768  if (MONTHCAL_UpdateToday(infoPtr, today)) infoPtr->todaySet = TRUE;
1769  }
1770 
1771  return 0;
1772 }
1773 
1774 /* returns calendar index containing specified point, or -1 if it's background */
1776 {
1777  RECT r;
1778  INT i;
1779 
1780  for (i = 0; i < MONTHCAL_GetCalCount(infoPtr); i++)
1781  {
1782  /* whole bounding rectangle allows some optimization to compute */
1783  r.left = infoPtr->calendars[i].title.left;
1784  r.top = infoPtr->calendars[i].title.top;
1785  r.bottom = infoPtr->calendars[i].days.bottom;
1786  r.right = infoPtr->calendars[i].days.right;
1787 
1788  if (PtInRect(&r, *pt)) return i;
1789  }
1790 
1791  return -1;
1792 }
1793 
1795 {
1796  dest->uHit = src->uHit;
1797  dest->st = src->st;
1798 
1799  if (dest->cbSize == sizeof(MCHITTESTINFO))
1800  memcpy(&dest->rc, &src->rc, sizeof(MCHITTESTINFO) - MCHITTESTINFO_V1_SIZE);
1801 
1802  return src->uHit;
1803 }
1804 
1805 static LRESULT
1807 {
1808  MCHITTESTINFO htinfo;
1809  SYSTEMTIME *ht_month;
1810  INT day, calIdx;
1811 
1812  if(!lpht || lpht->cbSize < MCHITTESTINFO_V1_SIZE) return -1;
1813 
1814  htinfo.st = st_null;
1815 
1816  /* we should preserve passed fields if hit area doesn't need them */
1817  if (lpht->cbSize == sizeof(MCHITTESTINFO))
1818  memcpy(&htinfo.rc, &lpht->rc, sizeof(MCHITTESTINFO) - MCHITTESTINFO_V1_SIZE);
1819 
1820  /* guess in what calendar we are */
1821  calIdx = MONTHCAL_GetCalendarFromPoint(infoPtr, &lpht->pt);
1822  if (calIdx == -1)
1823  {
1824  if (PtInRect(&infoPtr->todayrect, lpht->pt))
1825  {
1826  htinfo.uHit = MCHT_TODAYLINK;
1827  htinfo.rc = infoPtr->todayrect;
1828  }
1829  else
1830  /* outside of calendar area? What's left must be background :-) */
1831  htinfo.uHit = MCHT_CALENDARBK;
1832 
1833  return fill_hittest_info(&htinfo, lpht);
1834  }
1835 
1836  /* are we in the header? */
1837  if (PtInRect(&infoPtr->calendars[calIdx].title, lpht->pt)) {
1838  /* FIXME: buttons hittesting could be optimized cause maximum
1839  two calendars have buttons */
1840  if (calIdx == 0 && PtInRect(&infoPtr->titlebtnprev, lpht->pt))
1841  {
1842  htinfo.uHit = MCHT_TITLEBTNPREV;
1843  htinfo.rc = infoPtr->titlebtnprev;
1844  }
1845  else if (PtInRect(&infoPtr->titlebtnnext, lpht->pt))
1846  {
1847  htinfo.uHit = MCHT_TITLEBTNNEXT;
1848  htinfo.rc = infoPtr->titlebtnnext;
1849  }
1850  else if (PtInRect(&infoPtr->calendars[calIdx].titlemonth, lpht->pt))
1851  {
1852  htinfo.uHit = MCHT_TITLEMONTH;
1853  htinfo.rc = infoPtr->calendars[calIdx].titlemonth;
1854  htinfo.iOffset = calIdx;
1855  }
1856  else if (PtInRect(&infoPtr->calendars[calIdx].titleyear, lpht->pt))
1857  {
1858  htinfo.uHit = MCHT_TITLEYEAR;
1859  htinfo.rc = infoPtr->calendars[calIdx].titleyear;
1860  htinfo.iOffset = calIdx;
1861  }
1862  else
1863  {
1864  htinfo.uHit = MCHT_TITLE;
1865  htinfo.rc = infoPtr->calendars[calIdx].title;
1866  htinfo.iOffset = calIdx;
1867  }
1868 
1869  return fill_hittest_info(&htinfo, lpht);
1870  }
1871 
1872  ht_month = &infoPtr->calendars[calIdx].month;
1873  /* days area (including week days and week numbers) */
1874  day = MONTHCAL_GetDayFromPos(infoPtr, lpht->pt, calIdx);
1875  if (PtInRect(&infoPtr->calendars[calIdx].wdays, lpht->pt))
1876  {
1877  htinfo.uHit = MCHT_CALENDARDAY;
1878  htinfo.iOffset = calIdx;
1879  htinfo.st.wYear = ht_month->wYear;
1880  htinfo.st.wMonth = (day < 1) ? ht_month->wMonth -1 : ht_month->wMonth;
1881  htinfo.st.wDay = (day < 1) ?
1882  MONTHCAL_MonthLength(ht_month->wMonth-1, ht_month->wYear) - day : day;
1883 
1884  MONTHCAL_GetDayPos(infoPtr, &htinfo.st, &htinfo.iCol, &htinfo.iRow, calIdx);
1885  }
1886  else if(PtInRect(&infoPtr->calendars[calIdx].weeknums, lpht->pt))
1887  {
1888  htinfo.uHit = MCHT_CALENDARWEEKNUM;
1889  htinfo.st.wYear = ht_month->wYear;
1890  htinfo.iOffset = calIdx;
1891 
1892  if (day < 1)
1893  {
1894  htinfo.st.wMonth = ht_month->wMonth - 1;
1895  htinfo.st.wDay = MONTHCAL_MonthLength(ht_month->wMonth-1, ht_month->wYear) - day;
1896  }
1897  else if (day > MONTHCAL_MonthLength(ht_month->wMonth, ht_month->wYear))
1898  {
1899  htinfo.st.wMonth = ht_month->wMonth + 1;
1900  htinfo.st.wDay = day - MONTHCAL_MonthLength(ht_month->wMonth, ht_month->wYear);
1901  }
1902  else
1903  {
1904  htinfo.st.wMonth = ht_month->wMonth;
1905  htinfo.st.wDay = day;
1906  }
1907  }
1908  else if(PtInRect(&infoPtr->calendars[calIdx].days, lpht->pt))
1909  {
1910  htinfo.iOffset = calIdx;
1911  htinfo.st.wDay = ht_month->wDay;
1912  htinfo.st.wYear = ht_month->wYear;
1913  htinfo.st.wMonth = ht_month->wMonth;
1914  /* previous month only valid for first calendar */
1915  if (day < 1 && calIdx == 0)
1916  {
1917  htinfo.uHit = MCHT_CALENDARDATEPREV;
1918  MONTHCAL_GetPrevMonth(&htinfo.st);
1919  htinfo.st.wDay = MONTHCAL_MonthLength(htinfo.st.wMonth, htinfo.st.wYear) + day;
1920  }
1921  /* next month only valid for last calendar */
1922  else if (day > MONTHCAL_MonthLength(ht_month->wMonth, ht_month->wYear) &&
1923  calIdx == MONTHCAL_GetCalCount(infoPtr)-1)
1924  {
1925  htinfo.uHit = MCHT_CALENDARDATENEXT;
1926  MONTHCAL_GetNextMonth(&htinfo.st);
1927  htinfo.st.wDay = day - MONTHCAL_MonthLength(ht_month->wMonth, ht_month->wYear);
1928  }
1929  /* multiple calendars case - blank areas for previous/next month */
1930  else if (day < 1 || day > MONTHCAL_MonthLength(ht_month->wMonth, ht_month->wYear))
1931  {
1932  htinfo.uHit = MCHT_CALENDARBK;
1933  }
1934  else
1935  {
1936  htinfo.uHit = MCHT_CALENDARDATE;
1937  htinfo.st.wDay = day;
1938  }
1939 
1940  MONTHCAL_GetDayPos(infoPtr, &htinfo.st, &htinfo.iCol, &htinfo.iRow, calIdx);
1941  MONTHCAL_GetDayRectI(infoPtr, &htinfo.rc, htinfo.iCol, htinfo.iRow, calIdx);
1942  /* always update day of week */
1944  }
1945 
1946  return fill_hittest_info(&htinfo, lpht);
1947 }
1948 
1949 /* MCN_GETDAYSTATE notification helper */
1951 {
1953  NMDAYSTATE nmds;
1954 
1955  if (!(infoPtr->dwStyle & MCS_DAYSTATE)) return;
1956 
1957  nmds.nmhdr.hwndFrom = infoPtr->hwndSelf;
1958  nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
1959  nmds.nmhdr.code = MCN_GETDAYSTATE;
1960  nmds.cDayState = MONTHCAL_GetMonthRange(infoPtr, GMR_DAYSTATE, 0);
1961  nmds.prgDayState = state = heap_alloc_zero(nmds.cDayState * sizeof(MONTHDAYSTATE));
1962 
1963  MONTHCAL_GetMinDate(infoPtr, &nmds.stStart);
1964  nmds.stStart.wDay = 1;
1965 
1966  SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmds.nmhdr.idFrom, (LPARAM)&nmds);
1967  memcpy(infoPtr->monthdayState, nmds.prgDayState,
1968  MONTHCAL_GetMonthRange(infoPtr, GMR_DAYSTATE, 0)*sizeof(MONTHDAYSTATE));
1969 
1970  heap_free(state);
1971 }
1972 
1973 /* no valid range check performed */
1974 static void MONTHCAL_Scroll(MONTHCAL_INFO *infoPtr, INT delta, BOOL keep_selection)
1975 {
1976  INT i, selIdx = -1;
1977 
1978  for(i = 0; i < MONTHCAL_GetCalCount(infoPtr); i++)
1979  {
1980  /* save selection position to shift it later */
1981  if (selIdx == -1 && MONTHCAL_CompareMonths(&infoPtr->minSel, &infoPtr->calendars[i].month) == 0)
1982  selIdx = i;
1983 
1984  MONTHCAL_GetMonth(&infoPtr->calendars[i].month, delta);
1985  }
1986 
1987  if (keep_selection)
1988  return;
1989 
1990  /* selection is always shifted to first calendar */
1991  if (infoPtr->dwStyle & MCS_MULTISELECT)
1992  {
1993  SYSTEMTIME range[2];
1994 
1995  MONTHCAL_GetSelRange(infoPtr, range);
1996  MONTHCAL_GetMonth(&range[0], delta - selIdx);
1997  MONTHCAL_GetMonth(&range[1], delta - selIdx);
1998  MONTHCAL_SetSelRange(infoPtr, range);
1999  }
2000  else
2001  {
2002  SYSTEMTIME st = infoPtr->minSel;
2003 
2004  MONTHCAL_GetMonth(&st, delta - selIdx);
2005  MONTHCAL_SetCurSel(infoPtr, &st);
2006  }
2007 }
2008 
2009 static void MONTHCAL_GoToMonth(MONTHCAL_INFO *infoPtr, enum nav_direction direction)
2010 {
2011  INT delta = infoPtr->delta ? infoPtr->delta : MONTHCAL_GetCalCount(infoPtr);
2012  BOOL keep_selection;
2013  SYSTEMTIME st;
2014 
2015  TRACE("%s\n", direction == DIRECTION_BACKWARD ? "back" : "fwd");
2016 
2017  /* check if change allowed by range set */
2018  if(direction == DIRECTION_BACKWARD)
2019  {
2020  st = infoPtr->calendars[0].month;
2021  MONTHCAL_GetMonth(&st, -delta);
2022  }
2023  else
2024  {
2025  st = infoPtr->calendars[MONTHCAL_GetCalCount(infoPtr)-1].month;
2026  MONTHCAL_GetMonth(&st, delta);
2027  }
2028 
2029  if(!MONTHCAL_IsDateInValidRange(infoPtr, &st, FALSE)) return;
2030 
2031  keep_selection = infoPtr->dwStyle & MCS_NOSELCHANGEONNAV;
2032  MONTHCAL_Scroll(infoPtr, direction == DIRECTION_BACKWARD ? -delta : delta, keep_selection);
2033  MONTHCAL_NotifyDayState(infoPtr);
2034  if (!keep_selection)
2036 }
2037 
2038 static LRESULT
2040 {
2041  HMENU hMenu;
2042  POINT menupoint;
2043  WCHAR buf[32];
2044 
2045  hMenu = CreatePopupMenu();
2047  AppendMenuW(hMenu, MF_STRING|MF_ENABLED, 1, buf);
2048  menupoint.x = (short)LOWORD(lParam);
2049  menupoint.y = (short)HIWORD(lParam);
2050  ClientToScreen(infoPtr->hwndSelf, &menupoint);
2052  menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL))
2053  {
2054  if (infoPtr->dwStyle & MCS_MULTISELECT)
2055  {
2056  SYSTEMTIME range[2];
2057 
2058  range[0] = range[1] = infoPtr->todaysDate;
2059  MONTHCAL_SetSelRange(infoPtr, range);
2060  }
2061  else
2062  MONTHCAL_SetCurSel(infoPtr, &infoPtr->todaysDate);
2063 
2065  MONTHCAL_NotifySelect(infoPtr);
2066  }
2067 
2068  return 0;
2069 }
2070 
2071 /***
2072  * DESCRIPTION:
2073  * Subclassed edit control windproc function
2074  *
2075  * PARAMETER(S):
2076  * [I] hwnd : the edit window handle
2077  * [I] uMsg : the message that is to be processed
2078  * [I] wParam : first message parameter
2079  * [I] lParam : second message parameter
2080  *
2081  */
2083 {
2085 
2086  TRACE("(hwnd=%p, uMsg=%x, wParam=%lx, lParam=%lx)\n",
2087  hwnd, uMsg, wParam, lParam);
2088 
2089  switch (uMsg)
2090  {
2091  case WM_GETDLGCODE:
2093 
2094  case WM_DESTROY:
2095  {
2096  WNDPROC editProc = infoPtr->EditWndProc;
2097  infoPtr->EditWndProc = NULL;
2099  return CallWindowProcW(editProc, hwnd, uMsg, wParam, lParam);
2100  }
2101 
2102  case WM_KILLFOCUS:
2103  break;
2104 
2105  case WM_KEYDOWN:
2106  if ((VK_ESCAPE == (INT)wParam) || (VK_RETURN == (INT)wParam))
2107  break;
2108 
2109  default:
2110  return CallWindowProcW(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam);
2111  }
2112 
2113  SendMessageW(infoPtr->hWndYearUpDown, WM_CLOSE, 0, 0);
2114  SendMessageW(hwnd, WM_CLOSE, 0, 0);
2115  return 0;
2116 }
2117 
2118 /* creates updown control and edit box */
2119 static void MONTHCAL_EditYear(MONTHCAL_INFO *infoPtr, INT calIdx)
2120 {
2121  RECT *rc = &infoPtr->calendars[calIdx].titleyear;
2122  RECT *title = &infoPtr->calendars[calIdx].title;
2123 
2124  infoPtr->hWndYearEdit =
2126  rc->left + 3, (title->bottom + title->top - infoPtr->textHeight) / 2,
2127  rc->right - rc->left + 4,
2128  infoPtr->textHeight, infoPtr->hwndSelf,
2129  NULL, NULL, NULL);
2130 
2131  SendMessageW(infoPtr->hWndYearEdit, WM_SETFONT, (WPARAM)infoPtr->hBoldFont, TRUE);
2132 
2133  infoPtr->hWndYearUpDown =
2136  rc->right + 7, (title->bottom + title->top - infoPtr->textHeight) / 2,
2137  18, infoPtr->textHeight, infoPtr->hwndSelf,
2138  NULL, NULL, NULL);
2139 
2140  /* attach edit box */
2143  SendMessageW(infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM)infoPtr->hWndYearEdit, 0);
2144  SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, infoPtr->calendars[calIdx].month.wYear);
2145 
2146  /* subclass edit box */
2147  infoPtr->EditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hWndYearEdit,
2149 
2150  SetFocus(infoPtr->hWndYearEdit);
2151 }
2152 
2153 static LRESULT
2155 {
2156  MCHITTESTINFO ht;
2157  DWORD hit;
2158 
2159  /* Actually we don't need input focus for calendar, this is used to kill
2160  year updown and its buddy edit box */
2161  if (IsWindow(infoPtr->hWndYearUpDown))
2162  {
2163  SetFocus(infoPtr->hwndSelf);
2164  return 0;
2165  }
2166 
2167  SetCapture(infoPtr->hwndSelf);
2168 
2169  ht.cbSize = sizeof(MCHITTESTINFO);
2170  ht.pt.x = (short)LOWORD(lParam);
2171  ht.pt.y = (short)HIWORD(lParam);
2172 
2173  hit = MONTHCAL_HitTest(infoPtr, &ht);
2174 
2175  TRACE("%x at %s\n", hit, wine_dbgstr_point(&ht.pt));
2176 
2177  switch(hit)
2178  {
2179  case MCHT_TITLEBTNNEXT:
2181  infoPtr->status = MC_NEXTPRESSED;
2183  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
2184  return 0;
2185 
2186  case MCHT_TITLEBTNPREV:
2188  infoPtr->status = MC_PREVPRESSED;
2190  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
2191  return 0;
2192 
2193  case MCHT_TITLEMONTH:
2194  {
2195  HMENU hMenu = CreatePopupMenu();
2196  WCHAR buf[32];
2197  POINT menupoint;
2198  INT i;
2199 
2200  for (i = 0; i < 12; i++)
2201  {
2203  AppendMenuW(hMenu, MF_STRING|MF_ENABLED, i + 1, buf);
2204  }
2205  menupoint.x = ht.pt.x;
2206  menupoint.y = ht.pt.y;
2207  ClientToScreen(infoPtr->hwndSelf, &menupoint);
2209  menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL);
2210 
2211  if ((i > 0) && (i < 13) && infoPtr->calendars[ht.iOffset].month.wMonth != i)
2212  {
2213  INT delta = i - infoPtr->calendars[ht.iOffset].month.wMonth;
2214  SYSTEMTIME st;
2215 
2216  /* check if change allowed by range set */
2217  st = delta < 0 ? infoPtr->calendars[0].month :
2218  infoPtr->calendars[MONTHCAL_GetCalCount(infoPtr)-1].month;
2219  MONTHCAL_GetMonth(&st, delta);
2220 
2221  if (MONTHCAL_IsDateInValidRange(infoPtr, &st, FALSE))
2222  {
2223  MONTHCAL_Scroll(infoPtr, delta, FALSE);
2224  MONTHCAL_NotifyDayState(infoPtr);
2226  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
2227  }
2228  }
2229  return 0;
2230  }
2231  case MCHT_TITLEYEAR:
2232  {
2233  MONTHCAL_EditYear(infoPtr, ht.iOffset);
2234  return 0;
2235  }
2236  case MCHT_TODAYLINK:
2237  {
2238  if (infoPtr->dwStyle & MCS_MULTISELECT)
2239  {
2240  SYSTEMTIME range[2];
2241 
2242  range[0] = range[1] = infoPtr->todaysDate;
2243  MONTHCAL_SetSelRange(infoPtr, range);
2244  }
2245  else
2246  MONTHCAL_SetCurSel(infoPtr, &infoPtr->todaysDate);
2247 
2249  MONTHCAL_NotifySelect(infoPtr);
2250  return 0;
2251  }
2252  case MCHT_CALENDARDATENEXT:
2253  case MCHT_CALENDARDATEPREV:
2254  case MCHT_CALENDARDATE:
2255  {
2256  SYSTEMTIME st[2];
2257 
2258  MONTHCAL_CopyDate(&ht.st, &infoPtr->firstSel);
2259 
2260  st[0] = st[1] = ht.st;
2261  /* clear selection range */
2262  MONTHCAL_SetSelRange(infoPtr, st);
2263 
2264  infoPtr->status = MC_SEL_LBUTDOWN;
2265  MONTHCAL_SetDayFocus(infoPtr, &ht.st);
2266  return 0;
2267  }
2268  }
2269 
2270  return 1;
2271 }
2272 
2273 
2274 static LRESULT
2276 {
2277  NMHDR nmhdr;
2278  MCHITTESTINFO ht;
2279  DWORD hit;
2280 
2281  TRACE("\n");
2282 
2283  if(infoPtr->status & (MC_PREVPRESSED | MC_NEXTPRESSED)) {
2284  RECT *r;
2285 
2287  r = infoPtr->status & MC_PREVPRESSED ? &infoPtr->titlebtnprev : &infoPtr->titlebtnnext;
2288  infoPtr->status &= ~(MC_PREVPRESSED | MC_NEXTPRESSED);
2289 
2290  InvalidateRect(infoPtr->hwndSelf, r, FALSE);
2291  }
2292 
2293  ReleaseCapture();
2294 
2295  /* always send NM_RELEASEDCAPTURE notification */
2296  nmhdr.hwndFrom = infoPtr->hwndSelf;
2297  nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
2298  nmhdr.code = NM_RELEASEDCAPTURE;
2299  TRACE("Sent notification from %p to %p\n", infoPtr->hwndSelf, infoPtr->hwndNotify);
2300 
2301  SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhdr.idFrom, (LPARAM)&nmhdr);
2302 
2303  if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0;
2304 
2305  ht.cbSize = sizeof(MCHITTESTINFO);
2306  ht.pt.x = (short)LOWORD(lParam);
2307  ht.pt.y = (short)HIWORD(lParam);
2308  hit = MONTHCAL_HitTest(infoPtr, &ht);
2309 
2310  infoPtr->status = MC_SEL_LBUTUP;
2311  MONTHCAL_SetDayFocus(infoPtr, NULL);
2312 
2313  if((hit & MCHT_CALENDARDATE) == MCHT_CALENDARDATE)
2314  {
2315  SYSTEMTIME sel = infoPtr->minSel;
2316 
2317  /* will be invalidated here */
2318  MONTHCAL_SetCurSel(infoPtr, &ht.st);
2319 
2320  /* send MCN_SELCHANGE only if new date selected */
2321  if (!MONTHCAL_IsDateEqual(&sel, &ht.st))
2323 
2324  MONTHCAL_NotifySelect(infoPtr);
2325  }
2326 
2327  return 0;
2328 }
2329 
2330 
2331 static LRESULT
2333 {
2334  TRACE("%ld\n", id);
2335 
2336  switch(id) {
2337  case MC_PREVNEXTMONTHTIMER:
2338  if(infoPtr->status & MC_NEXTPRESSED) MONTHCAL_GoToMonth(infoPtr, DIRECTION_FORWARD);
2340  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
2341  break;
2342  case MC_TODAYUPDATETIMER:
2343  {
2344  SYSTEMTIME st;
2345 
2346  if(infoPtr->todaySet) return 0;
2347 
2348  GetLocalTime(&st);
2349  MONTHCAL_UpdateToday(infoPtr, &st);
2350 
2351  /* notification sent anyway */
2353 
2354  return 0;
2355  }
2356  default:
2357  ERR("got unknown timer %ld\n", id);
2358  break;
2359  }
2360 
2361  return 0;
2362 }
2363 
2364 
2365 static LRESULT
2367 {
2368  MCHITTESTINFO ht;
2369  SYSTEMTIME st_ht;
2370  INT hit;
2371  RECT r;
2372 
2373  if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0;
2374 
2375  ht.cbSize = sizeof(MCHITTESTINFO);
2376  ht.pt.x = (short)LOWORD(lParam);
2377  ht.pt.y = (short)HIWORD(lParam);
2378  ht.iOffset = -1;
2379 
2380  hit = MONTHCAL_HitTest(infoPtr, &ht);
2381 
2382  /* not on the calendar date numbers? bail out */
2383  TRACE("hit:%x\n",hit);
2384  if((hit & MCHT_CALENDARDATE) != MCHT_CALENDARDATE)
2385  {
2386  MONTHCAL_SetDayFocus(infoPtr, NULL);
2387  return 0;
2388  }
2389 
2390  st_ht = ht.st;
2391 
2392  /* if pointer is over focused day still there's nothing to do */
2393  if(!MONTHCAL_SetDayFocus(infoPtr, &ht.st)) return 0;
2394 
2395  MONTHCAL_GetDayRect(infoPtr, &ht.st, &r, ht.iOffset);
2396 
2397  if(infoPtr->dwStyle & MCS_MULTISELECT) {
2398  SYSTEMTIME st[2];
2399 
2400  MONTHCAL_GetSelRange(infoPtr, st);
2401 
2402  /* If we're still at the first selected date and range is empty, return.
2403  If range isn't empty we should change range to a single firstSel */
2404  if(MONTHCAL_IsDateEqual(&infoPtr->firstSel, &st_ht) &&
2405  MONTHCAL_IsDateEqual(&st[0], &st[1])) goto done;
2406 
2407  MONTHCAL_IsSelRangeValid(infoPtr, &st_ht, &infoPtr->firstSel, &st_ht);
2408 
2409  st[0] = infoPtr->firstSel;
2410  /* we should overwrite timestamp here */
2411  MONTHCAL_CopyDate(&st_ht, &st[1]);
2412 
2413  /* bounds will be swapped here if needed */
2414  MONTHCAL_SetSelRange(infoPtr, st);
2415 
2416  return 0;
2417  }
2418 
2419 done:
2420 
2421  /* FIXME: this should specify a rectangle containing only the days that changed
2422  using InvalidateRect */
2423  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
2424 
2425  return 0;
2426 }
2427 
2428 
2429 static LRESULT
2430 MONTHCAL_Paint(MONTHCAL_INFO *infoPtr, HDC hdc_paint)
2431 {
2432  HDC hdc;
2433  PAINTSTRUCT ps;
2434 
2435  if (hdc_paint)
2436  {
2437  GetClientRect(infoPtr->hwndSelf, &ps.rcPaint);
2438  hdc = hdc_paint;
2439  }
2440  else
2441  hdc = BeginPaint(infoPtr->hwndSelf, &ps);
2442 
2443  MONTHCAL_Refresh(infoPtr, hdc, &ps);
2444  if (!hdc_paint) EndPaint(infoPtr->hwndSelf, &ps);
2445  return 0;
2446 }
2447 
2448 static LRESULT
2450 {
2451  RECT rc;
2452 
2453  if (!GetClipBox(hdc, &rc)) return FALSE;
2454 
2455  FillRect(hdc, &rc, infoPtr->brushes[BrushBackground]);
2456 
2457  return TRUE;
2458 }
2459 
2460 static LRESULT
2462 {
2463  FIXME("Partial Stub: (hdc=%p options=0x%08x)\n", hdc, options);
2464 
2465  if ((options & PRF_CHECKVISIBLE) && !IsWindowVisible(infoPtr->hwndSelf))
2466  return 0;
2467 
2468  if (options & PRF_ERASEBKGND)
2469  MONTHCAL_EraseBkgnd(infoPtr, hdc);
2470 
2471  if (options & PRF_CLIENT)
2472  MONTHCAL_Paint(infoPtr, hdc);
2473 
2474  return 0;
2475 }
2476 
2477 static LRESULT
2479 {
2480  TRACE("\n");
2481 
2482  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
2483 
2484  return 0;
2485 }
2486 
2487 /* sets the size information */
2488 static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
2489 {
2490  static const WCHAR O0W[] = { '0','0',0 };
2491  RECT *title=&infoPtr->calendars[0].title;
2492  RECT *prev=&infoPtr->titlebtnprev;
2493  RECT *next=&infoPtr->titlebtnnext;
2494  RECT *titlemonth=&infoPtr->calendars[0].titlemonth;
2495  RECT *titleyear=&infoPtr->calendars[0].titleyear;
2496  RECT *wdays=&infoPtr->calendars[0].wdays;
2497  RECT *weeknumrect=&infoPtr->calendars[0].weeknums;
2498  RECT *days=&infoPtr->calendars[0].days;
2499  RECT *todayrect=&infoPtr->todayrect;
2500 
2501  INT xdiv, dx, dy, i, j, x, y, c_dx, c_dy;
2502  WCHAR buff[80];
2503  TEXTMETRICW tm;
2504  INT day_width;
2505  RECT client;
2506  HFONT font;
2507  SIZE size;
2508  HDC hdc;
2509 
2510  GetClientRect(infoPtr->hwndSelf, &client);
2511 
2512  hdc = GetDC(infoPtr->hwndSelf);
2513  font = SelectObject(hdc, infoPtr->hFont);
2514 
2515  /* get the height and width of each day's text */
2516  GetTextMetricsW(hdc, &tm);
2517  infoPtr->textHeight = tm.tmHeight + tm.tmExternalLeading + tm.tmInternalLeading;
2518 
2519  /* find widest day name for current locale and font */
2520  day_width = 0;
2521  for (i = 0; i < 7; i++)
2522  {
2523  SIZE sz;
2524 
2525  if (get_localized_dayname(infoPtr, i, buff, ARRAY_SIZE(buff)))
2526  {
2528  if (sz.cx > day_width) day_width = sz.cx;
2529  }
2530  else /* locale independent fallback on failure */
2531  {
2532  static const WCHAR sunW[] = { 'S','u','n' };
2533  GetTextExtentPoint32W(hdc, sunW, ARRAY_SIZE(sunW), &sz);
2534  day_width = sz.cx;
2535  break;
2536  }
2537  }
2538 
2539  day_width += 2;
2540 
2541  /* recalculate the height and width increments and offsets */
2542  size.cx = 0;
2543  GetTextExtentPoint32W(hdc, O0W, 2, &size);
2544 
2545  /* restore the originally selected font */
2546  SelectObject(hdc, font);
2547  ReleaseDC(infoPtr->hwndSelf, hdc);
2548 
2549  xdiv = (infoPtr->dwStyle & MCS_WEEKNUMBERS) ? 8 : 7;
2550 
2551  infoPtr->width_increment = max(day_width, size.cx * 2 + 4);
2552  infoPtr->height_increment = infoPtr->textHeight;
2553 
2554  /* calculate title area */
2555  title->top = 0;
2556  title->bottom = 3 * infoPtr->height_increment / 2;
2557  title->left = 0;
2558  title->right = infoPtr->width_increment * xdiv;
2559 
2560  /* set the dimensions of the next and previous buttons and center */
2561  /* the month text vertically */
2562  prev->top = next->top = title->top + 4;
2563  prev->bottom = next->bottom = title->bottom - 4;
2564  prev->left = title->left + 4;
2565  prev->right = prev->left + (title->bottom - title->top);
2566  next->right = title->right - 4;
2567  next->left = next->right - (title->bottom - title->top);
2568 
2569  /* titlemonth->left and right change based upon the current month
2570  and are recalculated in refresh as the current month may change
2571  without the control being resized */
2572  titlemonth->top = titleyear->top = title->top + (infoPtr->height_increment)/2;
2573  titlemonth->bottom = titleyear->bottom = title->bottom - (infoPtr->height_increment)/2;
2574 
2575  /* week numbers */
2576  weeknumrect->left = 0;
2577  weeknumrect->right = infoPtr->dwStyle & MCS_WEEKNUMBERS ? prev->right : 0;
2578 
2579  /* days abbreviated names */
2580  wdays->left = days->left = weeknumrect->right;
2581  wdays->right = days->right = wdays->left + 7 * infoPtr->width_increment;
2582  wdays->top = title->bottom;
2583  wdays->bottom = wdays->top + infoPtr->height_increment;
2584 
2585  days->top = weeknumrect->top = wdays->bottom;
2586  days->bottom = weeknumrect->bottom = days->top + 6 * infoPtr->height_increment;
2587 
2588  todayrect->left = 0;
2589  todayrect->right = title->right;
2590  todayrect->top = days->bottom;
2591  todayrect->bottom = days->bottom + infoPtr->height_increment;
2592 
2593  /* compute calendar count, update all calendars */
2594  x = (client.right + MC_CALENDAR_PADDING) / (title->right - title->left + MC_CALENDAR_PADDING);
2595  /* today label affects whole height */
2596  if (infoPtr->dwStyle & MCS_NOTODAY)
2597  y = (client.bottom + MC_CALENDAR_PADDING) / (days->bottom - title->top + MC_CALENDAR_PADDING);
2598  else
2599  y = (client.bottom - todayrect->bottom + todayrect->top + MC_CALENDAR_PADDING) /
2600  (days->bottom - title->top + MC_CALENDAR_PADDING);
2601 
2602  /* TODO: ensure that count is properly adjusted to fit 12 months constraint */
2603  if (x == 0) x = 1;
2604  if (y == 0) y = 1;
2605 
2606  if (x*y != MONTHCAL_GetCalCount(infoPtr))
2607  {
2608  infoPtr->dim.cx = x;
2609  infoPtr->dim.cy = y;
2610  infoPtr->calendars = heap_realloc(infoPtr->calendars, MONTHCAL_GetCalCount(infoPtr)*sizeof(CALENDAR_INFO));
2611 
2612  infoPtr->monthdayState = heap_realloc(infoPtr->monthdayState,
2613  MONTHCAL_GetMonthRange(infoPtr, GMR_DAYSTATE, 0)*sizeof(MONTHDAYSTATE));
2614  MONTHCAL_NotifyDayState(infoPtr);
2615 
2616  /* update pointers that we'll need */
2617  title = &infoPtr->calendars[0].title;
2618  wdays = &infoPtr->calendars[0].wdays;
2619  days = &infoPtr->calendars[0].days;
2620  }
2621 
2622  for (i = 1; i < MONTHCAL_GetCalCount(infoPtr); i++)
2623  {
2624  /* set months */
2625  infoPtr->calendars[i] = infoPtr->calendars[0];
2626  MONTHCAL_GetMonth(&infoPtr->calendars[i].month, i);
2627  }
2628 
2629  /* offset all rectangles to center in client area */
2630  c_dx = (client.right - x * title->right - MC_CALENDAR_PADDING * (x-1)) / 2;
2631  c_dy = (client.bottom - y * todayrect->bottom - MC_CALENDAR_PADDING * (y-1)) / 2;
2632 
2633  /* if calendar doesn't fit client area show it at left/top bounds */
2634  if (title->left + c_dx < 0) c_dx = 0;
2635  if (title->top + c_dy < 0) c_dy = 0;
2636 
2637  for (i = 0; i < y; i++)
2638  {
2639  for (j = 0; j < x; j++)
2640  {
2641  dx = j*(title->right - title->left + MC_CALENDAR_PADDING) + c_dx;
2642  dy = i*(days->bottom - title->top + MC_CALENDAR_PADDING) + c_dy;
2643 
2644  OffsetRect(&infoPtr->calendars[i*x+j].title, dx, dy);
2645  OffsetRect(&infoPtr->calendars[i*x+j].titlemonth, dx, dy);
2646  OffsetRect(&infoPtr->calendars[i*x+j].titleyear, dx, dy);
2647  OffsetRect(&infoPtr->calendars[i*x+j].wdays, dx, dy);
2648  OffsetRect(&infoPtr->calendars[i*x+j].weeknums, dx, dy);
2649  OffsetRect(&infoPtr->calendars[i*x+j].days, dx, dy);
2650  }
2651  }
2652 
2653  OffsetRect(prev, c_dx, c_dy);
2654  OffsetRect(next, (x-1)*(title->right - title->left + MC_CALENDAR_PADDING) + c_dx, c_dy);
2655 
2656  i = infoPtr->dim.cx * infoPtr->dim.cy - infoPtr->dim.cx;
2657  todayrect->left = infoPtr->calendars[i].title.left;
2658  todayrect->right = infoPtr->calendars[i].title.right;
2659  todayrect->top = infoPtr->calendars[i].days.bottom;
2660  todayrect->bottom = infoPtr->calendars[i].days.bottom + infoPtr->height_increment;
2661 
2662  TRACE("dx=%d dy=%d client[%s] title[%s] wdays[%s] days[%s] today[%s]\n",
2663  infoPtr->width_increment,infoPtr->height_increment,
2666  wine_dbgstr_rect(wdays),
2667  wine_dbgstr_rect(days),
2668  wine_dbgstr_rect(todayrect));
2669 }
2670 
2671 static LRESULT MONTHCAL_Size(MONTHCAL_INFO *infoPtr, int Width, int Height)
2672 {
2673  TRACE("(width=%d, height=%d)\n", Width, Height);
2674 
2675  MONTHCAL_UpdateSize(infoPtr);
2676  InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
2677 
2678  return 0;
2679 }
2680 
2682 {
2683  return (LRESULT)infoPtr->hFont;
2684 }
2685 
2687 {
2688  HFONT hOldFont;
2689  LOGFONTW lf;
2690 
2691  if (!hFont) return 0;
2692 
2693  hOldFont = infoPtr->hFont;
2694  infoPtr->hFont = hFont;
2695 
2696  GetObjectW(infoPtr->hFont, sizeof(lf), &lf);
2697  lf.lfWeight = FW_BOLD;
2698  infoPtr->hBoldFont = CreateFontIndirectW(&lf);
2699 
2700  MONTHCAL_UpdateSize(infoPtr);
2701 
2702  if (redraw)
2703  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
2704 
2705  return (LRESULT)hOldFont;
2706 }
2707 
2708 /* update theme after a WM_THEMECHANGED message */
2709 static LRESULT theme_changed (const MONTHCAL_INFO* infoPtr)
2710 {
2711  HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
2712  CloseThemeData (theme);
2713  OpenThemeData (infoPtr->hwndSelf, themeClass);
2714  return 0;
2715 }
2716 
2717 static INT MONTHCAL_StyleChanged(MONTHCAL_INFO *infoPtr, WPARAM wStyleType,
2718  const STYLESTRUCT *lpss)
2719 {
2720  TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
2721  wStyleType, lpss->styleOld, lpss->styleNew);
2722 
2723  if (wStyleType != GWL_STYLE) return 0;
2724 
2725  infoPtr->dwStyle = lpss->styleNew;
2726 
2727  /* make room for week numbers */
2728  if ((lpss->styleNew ^ lpss->styleOld) & (MCS_WEEKNUMBERS | MCS_SHORTDAYSOFWEEK))
2729  MONTHCAL_UpdateSize(infoPtr);
2730 
2731  return 0;
2732 }
2733 
2734 static INT MONTHCAL_StyleChanging(MONTHCAL_INFO *infoPtr, WPARAM wStyleType,
2735  STYLESTRUCT *lpss)
2736 {
2737  TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
2738  wStyleType, lpss->styleOld, lpss->styleNew);
2739 
2740  /* block MCS_MULTISELECT change */
2741  if ((lpss->styleNew ^ lpss->styleOld) & MCS_MULTISELECT)
2742  {
2743  if (lpss->styleOld & MCS_MULTISELECT)
2744  lpss->styleNew |= MCS_MULTISELECT;
2745  else
2746  lpss->styleNew &= ~MCS_MULTISELECT;
2747  }
2748 
2749  /* block MCS_DAYSTATE change */
2750  if ((lpss->styleNew ^ lpss->styleOld) & MCS_DAYSTATE)
2751  {
2752  if (lpss->styleOld & MCS_DAYSTATE)
2753  lpss->styleNew |= MCS_DAYSTATE;
2754  else
2755  lpss->styleNew &= ~MCS_DAYSTATE;
2756  }
2757 
2758  return 0;
2759 }
2760 
2761 /* FIXME: check whether dateMin/dateMax need to be adjusted. */
2762 static LRESULT
2764 {
2765  MONTHCAL_INFO *infoPtr;
2766 
2767  /* allocate memory for info structure */
2768  infoPtr = heap_alloc_zero(sizeof(*infoPtr));
2769  SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
2770 
2771  if (infoPtr == NULL) {
2772  ERR("could not allocate info memory!\n");
2773  return 0;
2774  }
2775 
2776  infoPtr->hwndSelf = hwnd;
2777  infoPtr->hwndNotify = lpcs->hwndParent;
2778  infoPtr->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
2779  infoPtr->dim.cx = infoPtr->dim.cy = 1;
2780  infoPtr->calendars = heap_alloc_zero(sizeof(CALENDAR_INFO));
2781  if (!infoPtr->calendars) goto fail;
2782  infoPtr->monthdayState = heap_alloc_zero(3 * sizeof(MONTHDAYSTATE));
2783  if (!infoPtr->monthdayState) goto fail;
2784 
2785  /* initialize info structure */
2786  /* FIXME: calculate systemtime ->> localtime(subtract timezoneinfo) */
2787 
2788  GetLocalTime(&infoPtr->todaysDate);
2789  MONTHCAL_SetFirstDayOfWeek(infoPtr, -1);
2790 
2791  infoPtr->maxSelCount = (infoPtr->dwStyle & MCS_MULTISELECT) ? 7 : 1;
2792 
2793  infoPtr->colors[MCSC_BACKGROUND] = comctl32_color.clrWindow;
2794  infoPtr->colors[MCSC_TEXT] = comctl32_color.clrWindowText;
2795  infoPtr->colors[MCSC_TITLEBK] = comctl32_color.clrActiveCaption;
2796  infoPtr->colors[MCSC_TITLETEXT] = comctl32_color.clrWindow;
2797  infoPtr->colors[MCSC_MONTHBK] = comctl32_color.clrWindow;
2798  infoPtr->colors[MCSC_TRAILINGTEXT] = comctl32_color.clrGrayText;
2799 
2800  infoPtr->brushes[BrushBackground] = CreateSolidBrush(infoPtr->colors[MCSC_BACKGROUND]);
2801  infoPtr->brushes[BrushTitle] = CreateSolidBrush(infoPtr->colors[MCSC_TITLEBK]);
2802  infoPtr->brushes[BrushMonth] = CreateSolidBrush(infoPtr->colors[MCSC_MONTHBK]);
2803 
2804  infoPtr->pens[PenRed] = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
2805  infoPtr->pens[PenText] = CreatePen(PS_SOLID, 1, infoPtr->colors[MCSC_TEXT]);
2806 
2807  infoPtr->minSel = infoPtr->todaysDate;
2808  infoPtr->maxSel = infoPtr->todaysDate;
2809  infoPtr->calendars[0].month = infoPtr->todaysDate;
2810  infoPtr->isUnicode = TRUE;
2811 
2812  /* setup control layout and day state data */
2813  MONTHCAL_UpdateSize(infoPtr);
2814 
2815  /* today auto update timer, to be freed only on control destruction */
2816  SetTimer(infoPtr->hwndSelf, MC_TODAYUPDATETIMER, MC_TODAYUPDATEDELAY, 0);
2817 
2818  OpenThemeData (infoPtr->hwndSelf, themeClass);
2819 
2820  return 0;
2821 
2822 fail:
2823  heap_free(infoPtr->monthdayState);
2824  heap_free(infoPtr->calendars);
2825  heap_free(infoPtr);
2826  return 0;
2827 }
2828 
2829 static LRESULT
2831 {
2832  INT i;
2833 
2834  /* free month calendar info data */
2835  heap_free(infoPtr->monthdayState);
2836  heap_free(infoPtr->calendars);
2837  SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0);
2838 
2839  CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
2840 
2841  for (i = 0; i < BrushLast; i++) DeleteObject(infoPtr->brushes[i]);
2842  for (i = 0; i < PenLast; i++) DeleteObject(infoPtr->pens[i]);
2843 
2844  heap_free(infoPtr);
2845  return 0;
2846 }
2847 
2848 /*
2849  * Handler for WM_NOTIFY messages
2850  */
2851 static LRESULT
2853 {
2854  /* notification from year edit updown */
2855  if (hdr->code == UDN_DELTAPOS)
2856  {
2857  NMUPDOWN *nmud = (NMUPDOWN*)hdr;
2858 
2859  if (hdr->hwndFrom == infoPtr->hWndYearUpDown && nmud->iDelta)
2860  {
2861  /* year value limits are set up explicitly after updown creation */
2862  MONTHCAL_Scroll(infoPtr, 12 * nmud->iDelta, FALSE);
2863  MONTHCAL_NotifyDayState(infoPtr);
2865  }
2866  }
2867  return 0;
2868 }
2869 
2870 static inline BOOL
2872 {
2873  BOOL prev = infoPtr->isUnicode;
2874  infoPtr->isUnicode = isUnicode;
2875  return prev;
2876 }
2877 
2878 static inline BOOL
2880 {
2881  return infoPtr->isUnicode;
2882 }
2883 
2884 static LRESULT WINAPI
2886 {
2888 
2889  TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam);
2890 
2891  if (!infoPtr && (uMsg != WM_CREATE))
2892  return DefWindowProcW(hwnd, uMsg, wParam, lParam);
2893  switch(uMsg)
2894  {
2895  case MCM_GETCURSEL:
2896  return MONTHCAL_GetCurSel(infoPtr, (LPSYSTEMTIME)lParam);
2897 
2898  case MCM_SETCURSEL:
2899  return MONTHCAL_SetCurSel(infoPtr, (LPSYSTEMTIME)lParam);
2900 
2901  case MCM_GETMAXSELCOUNT:
2902  return MONTHCAL_GetMaxSelCount(infoPtr);
2903 
2904  case MCM_SETMAXSELCOUNT:
2905  return MONTHCAL_SetMaxSelCount(infoPtr, wParam);
2906 
2907  case MCM_GETSELRANGE:
2908  return MONTHCAL_GetSelRange(infoPtr, (LPSYSTEMTIME)lParam);
2909 
2910  case MCM_SETSELRANGE:
2911  return MONTHCAL_SetSelRange(infoPtr, (LPSYSTEMTIME)lParam);
2912 
2913  case MCM_GETMONTHRANGE:
2914  return MONTHCAL_GetMonthRange(infoPtr, wParam, (SYSTEMTIME*)lParam);
2915 
2916  case MCM_SETDAYSTATE:
2918 
2919  case MCM_GETMINREQRECT:
2920  return MONTHCAL_GetMinReqRect(infoPtr, (LPRECT)lParam);
2921 
2922  case MCM_GETCOLOR:
2923  return MONTHCAL_GetColor(infoPtr, wParam);
2924 
2925  case MCM_SETCOLOR:
2926  return MONTHCAL_SetColor(infoPtr, wParam, (COLORREF)lParam);
2927 
2928  case MCM_GETTODAY:
2929  return MONTHCAL_GetToday(infoPtr, (LPSYSTEMTIME)lParam);
2930 
2931  case MCM_SETTODAY:
2932  return MONTHCAL_SetToday(infoPtr, (LPSYSTEMTIME)lParam);
2933 
2934  case MCM_HITTEST:
2935  return MONTHCAL_HitTest(infoPtr, (PMCHITTESTINFO)lParam);
2936 
2937  case MCM_GETFIRSTDAYOFWEEK:
2938  return MONTHCAL_GetFirstDayOfWeek(infoPtr);
2939 
2940  case MCM_SETFIRSTDAYOFWEEK:
2941  return MONTHCAL_SetFirstDayOfWeek(infoPtr, (INT)lParam);
2942 
2943  case MCM_GETRANGE:
2944  return MONTHCAL_GetRange(infoPtr, (LPSYSTEMTIME)lParam);
2945 
2946  case MCM_SETRANGE:
2947  return MONTHCAL_SetRange(infoPtr, (SHORT)wParam, (LPSYSTEMTIME)lParam);
2948 
2949  case MCM_GETMONTHDELTA:
2950  return MONTHCAL_GetMonthDelta(infoPtr);
2951 
2952  case MCM_SETMONTHDELTA:
2953  return MONTHCAL_SetMonthDelta(infoPtr, wParam);
2954 
2955  case MCM_GETMAXTODAYWIDTH:
2956  return MONTHCAL_GetMaxTodayWidth(infoPtr);
2957 
2958  case MCM_SETUNICODEFORMAT:
2959  return MONTHCAL_SetUnicodeFormat(infoPtr, (BOOL)wParam);
2960 
2961  case MCM_GETUNICODEFORMAT:
2962  return MONTHCAL_GetUnicodeFormat(infoPtr);
2963 
2964  case MCM_GETCALENDARCOUNT:
2965  return MONTHCAL_GetCalCount(infoPtr);
2966 
2967  case WM_GETDLGCODE:
2969 
2970  case WM_RBUTTONUP:
2971  return MONTHCAL_RButtonUp(infoPtr, lParam);
2972 
2973  case WM_LBUTTONDOWN:
2974  return MONTHCAL_LButtonDown(infoPtr, lParam);
2975 
2976  case WM_MOUSEMOVE:
2977  return MONTHCAL_MouseMove(infoPtr, lParam);
2978 
2979  case WM_LBUTTONUP:
2980  return MONTHCAL_LButtonUp(infoPtr, lParam);
2981 
2982  case WM_PAINT:
2983  return MONTHCAL_Paint(infoPtr, (HDC)wParam);
2984 
2985  case WM_PRINTCLIENT:
2986  return MONTHCAL_PrintClient(infoPtr, (HDC)wParam, (DWORD)lParam);
2987 
2988  case WM_ERASEBKGND:
2989  return MONTHCAL_EraseBkgnd(infoPtr, (HDC)wParam);
2990 
2991  case WM_SETFOCUS:
2992  return MONTHCAL_SetFocus(infoPtr);
2993 
2994  case WM_SIZE:
2995  return MONTHCAL_Size(infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
2996 
2997  case WM_NOTIFY:
2998  return MONTHCAL_Notify(infoPtr, (NMHDR*)lParam);
2999 
3000  case WM_CREATE:
3002 
3003  case WM_SETFONT:
3004  return MONTHCAL_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam);
3005 
3006  case WM_GETFONT:
3007  return MONTHCAL_GetFont(infoPtr);
3008 
3009  case WM_TIMER:
3010  return MONTHCAL_Timer(infoPtr, wParam);
3011 
3012  case WM_THEMECHANGED:
3013  return theme_changed (infoPtr);
3014 
3015  case WM_DESTROY:
3016  return MONTHCAL_Destroy(infoPtr);
3017 
3018  case WM_SYSCOLORCHANGE:
3020  return 0;
3021 
3022  case WM_STYLECHANGED:
3023  return MONTHCAL_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
3024 
3025  case WM_STYLECHANGING:
3027 
3028  default:
3029  if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
3030  ERR( "unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
3031  return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3032  }
3033 }
3034 
3035 
3036 void
3038 {
3039  WNDCLASSW wndClass;
3040 
3041  ZeroMemory(&wndClass, sizeof(WNDCLASSW));
3042  wndClass.style = CS_GLOBALCLASS;
3043  wndClass.lpfnWndProc = MONTHCAL_WindowProc;
3044  wndClass.cbClsExtra = 0;
3045  wndClass.cbWndExtra = sizeof(MONTHCAL_INFO *);
3046  wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
3047  wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
3048  wndClass.lpszClassName = MONTHCAL_CLASSW;
3049 
3050  RegisterClassW(&wndClass);
3051 }
3052 
3053 
3054 void
3056 {
3058 }
HGDIOBJ WINAPI GetStockObject(_In_ int)
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
static LRESULT MONTHCAL_EraseBkgnd(const MONTHCAL_INFO *infoPtr, HDC hdc)
Definition: monthcal.c:2449
static LRESULT MONTHCAL_PrintClient(MONTHCAL_INFO *infoPtr, HDC hdc, DWORD options)
Definition: monthcal.c:2461
BOOL todaySet
Definition: monthcal.c:126
#define WS_DISABLED
Definition: pedump.c:621
#define MCSC_MONTHBK
Definition: commctrl.h:4207
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
COLORREF WINAPI GetBkColor(_In_ HDC)
Definition: dc.c:954
#define MCN_SELECT
Definition: commctrl.h:4301
#define WM_SYSCOLORCHANGE
Definition: winuser.h:1608
DWORD * LPMONTHDAYSTATE
Definition: commctrl.h:4176
#define IDM_TODAY
Definition: comctl32.h:77
#define max(a, b)
Definition: svc.c:63
#define MCHT_CALENDARDATENEXT
Definition: commctrl.h:4249
#define TRUE
Definition: types.h:120
#define DLGC_WANTCHARS
Definition: winuser.h:2593
#define WC_EDITW
Definition: commctrl.h:4683
HPEN WINAPI CreatePen(_In_ int, _In_ int, _In_ COLORREF)
static LRESULT MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
Definition: monthcal.c:2154
SYSTEMTIME todaysDate
Definition: monthcal.c:125
char hdr[14]
Definition: iptest.cpp:33
static const SYSTEMTIME max_allowed_date
Definition: monthcal.c:154
BOOL WINAPI GetTextMetricsW(_In_ HDC, _Out_ LPTEXTMETRICW)
Definition: text.c:221
#define MCHT_CALENDARDATE
Definition: commctrl.h:4248
static LRESULT MONTHCAL_Size(MONTHCAL_INFO *infoPtr, int Width, int Height)
Definition: monthcal.c:2671
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
RECT titlebtnprev
Definition: monthcal.c:138
#define LOCALE_SABBREVMONTHNAME1
Definition: winnls.h:104
static LRESULT MONTHCAL_GetToday(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *today)
Definition: monthcal.c:1722
long y
Definition: polytest.cpp:48
int textHeight
Definition: monthcal.c:113
UINT style
Definition: winuser.h:3151
#define WM_GETDLGCODE
Definition: winuser.h:1671
BOOL WINAPI ClientToScreen(_In_ HWND, _Inout_ LPPOINT)
#define WM_LBUTTONDOWN
Definition: winuser.h:1758
#define MCHT_TITLEBTNPREV
Definition: commctrl.h:4245
static INT MONTHCAL_StyleChanging(MONTHCAL_INFO *infoPtr, WPARAM wStyleType, STYLESTRUCT *lpss)
Definition: monthcal.c:2734
static UINT fill_hittest_info(const MCHITTESTINFO *src, MCHITTESTINFO *dest)
Definition: monthcal.c:1794
BOOL WINAPI OffsetRect(_Inout_ LPRECT, _In_ int, _In_ int)
BOOL WINAPI UnregisterClassW(_In_ LPCWSTR, HINSTANCE)
BOOL WINAPI IsWindow(_In_opt_ HWND)
static LRESULT MONTHCAL_SetDayState(const MONTHCAL_INFO *infoPtr, INT months, MONTHDAYSTATE *states)
Definition: monthcal.c:1530
static void MONTHCAL_PaintButton(MONTHCAL_INFO *infoPtr, HDC hdc, enum nav_direction button)
Definition: monthcal.c:829
long x
Definition: polytest.cpp:48
static LRESULT MONTHCAL_GetSelRange(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *range)
Definition: monthcal.c:1639
WORD wMonth
Definition: winbase.h:878
HDC WINAPI GetDC(_In_opt_ HWND)
BOOL WINAPI Rectangle(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int)
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
Definition: mk_font.cpp:20
static LRESULT MONTHCAL_SetMonthDelta(MONTHCAL_INFO *infoPtr, INT delta)
Definition: monthcal.c:1365
#define MCM_GETMINREQRECT
Definition: commctrl.h:4196
#define MCSC_TEXT
Definition: commctrl.h:4204
#define MCHT_CALENDARWEEKNUM
Definition: commctrl.h:4252
static LRESULT MONTHCAL_SetColor(MONTHCAL_INFO *infoPtr, UINT index, COLORREF color)
Definition: monthcal.c:1307
#define pt(x, y)
Definition: drawing.c:79
#define TPM_LEFTALIGN
Definition: winuser.h:2352
SYSTEMTIME minDate
Definition: monthcal.c:134
#define MCHT_TITLEBTNNEXT
Definition: commctrl.h:4244
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
#define LOCALE_SABBREVDAYNAME1
Definition: winnls.h:84
#define TPM_RETURNCMD
Definition: winuser.h:2362
#define LOCALE_USER_DEFAULT
GLuint GLuint GLsizei count
Definition: gl.h:1545
WORD wDayOfWeek
Definition: winbase.h:879
#define DATE_SHORTDATE
Definition: winnls.h:193
GLint dy
Definition: linetemp.h:97
static void MONTHCAL_NotifyDayState(MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:1950
static DOUBLE day(DOUBLE time)
Definition: date.c:117
#define NULL_BRUSH
Definition: wingdi.h:900
static LRESULT MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, INT day)
Definition: monthcal.c:1405
#define MCS_SHORTDAYSOFWEEK
Definition: commctrl.h:4309
const GLint * first
Definition: glext.h:5794
#define WARN(fmt,...)
Definition: debug.h:111
#define MCM_GETRANGE
Definition: commctrl.h:4258
#define NM_RELEASEDCAPTURE
Definition: commctrl.h:141
BOOL WINAPI DrawFocusRect(_In_ HDC, _In_ LPCRECT)
DWORD button
Definition: button.c:166
#define MCM_SETMAXSELCOUNT
Definition: commctrl.h:4186
static HDC
Definition: imagelist.c:92
#define DFCS_INACTIVE
Definition: winuser.h:502
#define CALLBACK
Definition: compat.h:27
#define MF_STRING
Definition: winuser.h:138
static LRESULT MONTHCAL_Create(HWND hwnd, LPCREATESTRUCTW lpcs)
Definition: monthcal.c:2763
HWND hwndSelf
Definition: monthcal.c:104
LONG top
Definition: windef.h:307
static const SYSTEMTIME min_allowed_date
Definition: monthcal.c:155
static LRESULT MONTHCAL_Paint(MONTHCAL_INFO *infoPtr, HDC hdc_paint)
Definition: monthcal.c:2430
static LRESULT theme_changed(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:2709
#define MONTHCAL_CLASSW
Definition: commctrl.h:4171
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1497
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
static LRESULT MONTHCAL_GetMonthRange(const MONTHCAL_INFO *infoPtr, DWORD flag, SYSTEMTIME *st)
Definition: monthcal.c:674
static HTHEME(WINAPI *pOpenThemeDataEx)(HWND
#define ZeroMemory
Definition: winbase.h:1642
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
#define MCM_SETUNICODEFORMAT
Definition: commctrl.h:4272
BOOL WINAPI LineTo(_In_ HDC, _In_ int, _In_ int)
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
int cbClsExtra
Definition: winuser.h:3153
static LRESULT MONTHCAL_GetCurSel(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
Definition: monthcal.c:1543
HWND WINAPI SetFocus(_In_opt_ HWND)
INT maxSelCount
Definition: monthcal.c:129
BOOL WINAPI DrawFrameControl(_In_ HDC, _Inout_ LPRECT, _In_ UINT, _In_ UINT)
#define MCHT_TODAYLINK
Definition: commctrl.h:4234
UINT_PTR WPARAM
Definition: windef.h:207
RECT weeknums
Definition: monthcal.c:97
#define ES_READONLY
Definition: pedump.c:675
#define WS_CHILD
Definition: pedump.c:617
#define MCN_SELCHANGE
Definition: commctrl.h:4287
#define GetWindowLongPtrW
Definition: winuser.h:4804
__u16 time
Definition: mkdosfs.c:366
static COLORREF MONTHCAL_GetColor(const MONTHCAL_INFO *infoPtr, UINT index)
Definition: monthcal.c:1298
LONG left
Definition: windef.h:306
BOOL firstDaySet
Definition: monthcal.c:120
#define MCM_SETSELRANGE
Definition: commctrl.h:4190
BOOL WINAPI EndPaint(_In_ HWND, _In_ const PAINTSTRUCT *)
LPMONTHDAYSTATE prgDayState
Definition: commctrl.h:4294
#define cmp(status, error)
Definition: error.c:114
static BOOL MONTHCAL_SetDayFocus(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *st)
Definition: monthcal.c:731
#define MCM_GETUNICODEFORMAT
Definition: commctrl.h:4274
#define VK_ESCAPE
Definition: winuser.h:2189
LONG right
Definition: windef.h:308
#define MCM_SETRANGE
Definition: commctrl.h:4260
#define lstrlenW
Definition: compat.h:415
static LRESULT MONTHCAL_GetMaxTodayWidth(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:1450
HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect)
Definition: draw.c:128
#define MCS_DAYSTATE
Definition: commctrl.h:4303
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
#define COLOR_WINDOW
Definition: winuser.h:908
int32_t INT
Definition: typedefs.h:56
static void MONTHCAL_PaintLeadTrailMonths(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
Definition: monthcal.c:1119
#define VK_RETURN
Definition: winuser.h:2176
static INT MONTHCAL_GetCalendarFromPoint(const MONTHCAL_INFO *infoPtr, const POINT *pt)
Definition: monthcal.c:1775
static void * heap_realloc(void *mem, size_t len)
Definition: appwiz.h:70
& rect
Definition: startmenu.cpp:1413
WPARAM wParam
Definition: combotst.c:138
int selection
Definition: ctm.c:92
HFONT hFont
Definition: main.c:53
const GLfloat * m
Definition: glext.h:10848
#define WM_PRINTCLIENT
Definition: richedit.h:70
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
WINE_UNICODE_INLINE int strncmpW(const WCHAR *str1, const WCHAR *str2, int n)
Definition: unicode.h:235
static LRESULT MONTHCAL_RButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam)
Definition: monthcal.c:2039
#define MC_TODAYUPDATEDELAY
Definition: monthcal.c:64
static void MONTHCAL_PaintTodayTitle(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
Definition: monthcal.c:1061
BOOL WINAPI AppendMenuW(_In_ HMENU, _In_ UINT, _In_ UINT_PTR, _In_opt_ LPCWSTR)
static void MONTHCAL_GetPrevMonth(SYSTEMTIME *date)
Definition: monthcal.c:505
#define MCSC_TITLETEXT
Definition: commctrl.h:4206
static void MONTHCAL_CopyDate(const SYSTEMTIME *from, SYSTEMTIME *to)
Definition: monthcal.c:282
static void MONTHCAL_GetMaxDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
Definition: monthcal.c:534
INT WINAPI GetLocaleInfoW(LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len)
Definition: lang.c:1098
UINT code
Definition: winuser.h:3134
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:975
COLORREF clrWindowText
Definition: comctl32.h:170
BOOL WINAPI MoveToEx(_In_ HDC, _In_ int, _In_ int, _Out_opt_ LPPOINT)
HWND hwndNotify
Definition: monthcal.c:140
SYSTEMTIME stSelEnd
Definition: commctrl.h:4284
ATOM WINAPI RegisterClassW(_In_ CONST WNDCLASSW *)
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
#define PS_SOLID
Definition: wingdi.h:585
#define DFCS_PUSHED
Definition: winuser.h:503
DWORD dwHighDateTime
Definition: mapidefs.h:66
BOOL WINAPI AdjustWindowRect(_Inout_ LPRECT, _In_ DWORD, _In_ BOOL)
WORD wYear
Definition: winbase.h:877
int WINAPI SetBkMode(_In_ HDC, _In_ int)
Definition: dc.c:1032
#define TPM_RIGHTBUTTON
Definition: winuser.h:2355
DWORD LCTYPE
Definition: winnls.h:514
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define MCM_GETCURSEL
Definition: commctrl.h:4180
#define LOCALE_SMONTHNAME1
Definition: winnls.h:91
GLenum GLint GLuint mask
Definition: glext.h:6028
COLORREF clrActiveCaption
Definition: comctl32.h:172
static BOOL MONTHCAL_UpdateToday(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *today)
Definition: monthcal.c:1739
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define DT_LEFT
Definition: winuser.h:534
#define DT_CALCRECT
Definition: winuser.h:526
unsigned int BOOL
Definition: ntddk_ex.h:94
WCHAR strW[12]
Definition: clipboard.c:2029
long LONG
Definition: pedump.c:60
#define UDS_NOTHOUSANDS
Definition: commctrl.h:2134
GLuint color
Definition: glext.h:6243
static LRESULT WINAPI MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: monthcal.c:2885
#define MC_NEXTPRESSED
Definition: monthcal.c:60
short SHORT
Definition: pedump.c:59
HDC WINAPI BeginPaint(_In_ HWND, _Out_ LPPAINTSTRUCT)
HFONT hBoldFont
Definition: monthcal.c:112
UINT_PTR idFrom
Definition: winuser.h:3133
#define debugstr_w
Definition: kernel32.h:32
WNDPROC lpfnWndProc
Definition: winuser.h:3152
#define MC_CALENDAR_PADDING
Definition: monthcal.c:69
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
#define FIXME(fmt,...)
Definition: debug.h:110
static const WCHAR themeClass[]
Definition: monthcal.c:149
#define TRANSPARENT
Definition: wingdi.h:949
RECT titleyear
Definition: monthcal.c:94
LONG WINAPI GetWindowLongW(_In_ HWND, _In_ int)
WORD wMinute
Definition: winbase.h:882
#define MAKELONG(a, b)
Definition: typedefs.h:248
static void MONTHCAL_Scroll(MONTHCAL_INFO *infoPtr, INT delta, BOOL keep_selection)
Definition: monthcal.c:1974
#define UDS_ARROWKEYS
Definition: commctrl.h:2132
static void MONTHCAL_GoToMonth(MONTHCAL_INFO *infoPtr, enum nav_direction direction)
Definition: monthcal.c:2009
#define strstrW(d, s)
Definition: unicode.h:32
#define MCM_SETFIRSTDAYOFWEEK
Definition: commctrl.h:4254
#define MCM_GETCALENDARCOUNT
Definition: commctrl.h:4270
#define MCM_HITTEST
Definition: commctrl.h:4214
static BOOL MONTHCAL_IsSelRangeValid(const MONTHCAL_INFO *infoPtr, const SYSTEMTIME *range0, const SYSTEMTIME *range1, SYSTEMTIME *adjust)
Definition: monthcal.c:402
smooth NULL
Definition: ftsmooth.c:416
HFONT WINAPI CreateFontIndirectW(_In_ const LOGFONTW *)
#define WM_GETFONT
Definition: winuser.h:1633
static LRESULT MONTHCAL_SetMaxSelCount(MONTHCAL_INFO *infoPtr, INT max)
Definition: monthcal.c:1625
SYSTEMTIME stSelStart
Definition: commctrl.h:4283
static LRESULT MONTHCAL_SetSelRange(MONTHCAL_INFO *infoPtr, SYSTEMTIME *range)
Definition: monthcal.c:1658
LONG cx
Definition: windef.h:334
#define WM_KEYDOWN
Definition: winuser.h:1697
LPCWSTR lpszClassName
Definition: winuser.h:3160
LONG_PTR LPARAM
Definition: windef.h:208
#define GMR_DAYSTATE
Definition: commctrl.h:4312
#define MC_TODAYUPDATETIMER
Definition: monthcal.c:67
VOID WINAPI GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:286
#define UDM_SETRANGE
Definition: commctrl.h:2137
static LRESULT MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
Definition: monthcal.c:1806
HPEN pens[PenLast]
Definition: monthcal.c:109
GLuint index
Definition: glext.h:6031
#define DT_VCENTER
Definition: winuser.h:543
HWND hWndYearUpDown
Definition: monthcal.c:142
SYSTEMTIME maxSel
Definition: monthcal.c:131
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define WM_DESTROY
Definition: winuser.h:1591
#define MCM_SETCURSEL
Definition: commctrl.h:4182
#define MCHT_CALENDARBK
Definition: commctrl.h:4247
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
static BOOL MONTHCAL_IsDateInValidRange(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date, BOOL fix)
Definition: monthcal.c:351
static void MONTHCAL_GetDayPos(const MONTHCAL_INFO *infoPtr, const SYSTEMTIME *date, INT *col, INT *row, INT calIdx)
Definition: monthcal.c:594
#define MC_PREVPRESSED
Definition: monthcal.c:59
#define MCM_SETCOLOR
Definition: commctrl.h:4198
static LRESULT MONTHCAL_GetFont(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:2681
static LRESULT MONTHCAL_Notify(MONTHCAL_INFO *infoPtr, NMHDR *hdr)
Definition: monthcal.c:2852
static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
Definition: monthcal.c:1229
#define MCS_WEEKNUMBERS
Definition: commctrl.h:4305
#define MCM_GETTODAY
Definition: commctrl.h:4212
const char * wine_dbgstr_point(const POINT *guid)
int MONTHCAL_MonthLength(int month, int year)
Definition: monthcal.c:217
static LRESULT MONTHCAL_SetRange(MONTHCAL_INFO *infoPtr, SHORT limits, SYSTEMTIME *range)
Definition: monthcal.c:1456
static LRESULT MONTHCAL_GetMinReqRect(const MONTHCAL_INFO *infoPtr, RECT *rect)
Definition: monthcal.c:1277
#define MCHT_TITLE
Definition: commctrl.h:4232
#define TRACE(s)
Definition: solgame.cpp:4
BOOL WINAPI FileTimeToSystemTime(IN CONST FILETIME *lpFileTime, OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:188
#define WM_KILLFOCUS
Definition: winuser.h:1596
GLsizeiptr size
Definition: glext.h:5919
SYSTEMTIME firstSel
Definition: monthcal.c:128
LONG WINAPI CompareFileTime(IN CONST FILETIME *lpFileTime1, IN CONST FILETIME *lpFileTime2)
Definition: time.c:106
#define MCS_NOSELCHANGEONNAV
Definition: monthcal.c:55
WINE_DEFAULT_DEBUG_CHANNEL(monthcal)
static LRESULT CALLBACK EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: monthcal.c:2082
SYSTEMTIME minSel
Definition: monthcal.c:130
int width_increment
Definition: monthcal.c:115
int cbWndExtra
Definition: winuser.h:3154
static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:2488
#define PRF_ERASEBKGND
Definition: winuser.h:2501
__wchar_t WCHAR
Definition: xmlstorage.h:180
DWORD dwStyle
Definition: monthcal.c:105
#define WM_SIZE
Definition: winuser.h:1593
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
WNDPROC EditWndProc
Definition: monthcal.c:143
DWORD COLORREF
Definition: windef.h:300
#define WM_TIMER
Definition: winuser.h:1724
RECT titlemonth
Definition: monthcal.c:93
#define MF_ENABLED
Definition: winuser.h:128
#define WM_CLOSE
Definition: winuser.h:1603
#define CS_GLOBALCLASS
Definition: winuser.h:647
DWORD rangeValid
Definition: monthcal.c:133
#define RGB(r, g, b)
Definition: wingdi.h:2939
#define MCS_MULTISELECT
Definition: commctrl.h:4304
#define WINAPI
Definition: msvc.h:6
const char * wine_dbgstr_rect(const RECT *rect)
static LRESULT MONTHCAL_GetMonthDelta(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:1353
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
#define DAYSTO100NSECS(days)
Definition: monthcal.c:72
HWND hWndYearEdit
Definition: monthcal.c:141
static FILE * client
Definition: client.c:41
unsigned short WORD
Definition: ntddk_ex.h:93
#define MCM_SETDAYSTATE
Definition: commctrl.h:4194
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint left
Definition: glext.h:7726
#define DFCS_SCROLLRIGHT
Definition: winuser.h:492
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2074
int WINAPI GetClipBox(_In_ HDC, _Out_ LPRECT)
BOOL WINAPI UnionRect(_Out_ LPRECT, _In_ LPCRECT, _In_ LPCRECT)
static int MONTHCAL_MonthDiff(const SYSTEMTIME *left, const SYSTEMTIME *right)
Definition: monthcal.c:210
#define PRF_CHECKVISIBLE
Definition: winuser.h:2498
static void MONTHCAL_NotifySelectionChange(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:171
GLdouble GLdouble right
Definition: glext.h:10859
#define OBJ_FONT
Definition: objidl.idl:1414
#define WM_RBUTTONUP
Definition: winuser.h:1762
SYSTEMTIME month
Definition: monthcal.c:99
HTHEME WINAPI OpenThemeData(HWND hwnd, LPCWSTR classlist)
Definition: system.c:835
COMCTL32_SysColor comctl32_color
Definition: commctrl.c:82
SYSTEMTIME focusedSel
Definition: monthcal.c:132
#define TPM_NONOTIFY
Definition: winuser.h:2361
static void MONTHCAL_GetNextMonth(SYSTEMTIME *date)
Definition: monthcal.c:499
WORD wSecond
Definition: winbase.h:883
#define WM_PAINT
Definition: winuser.h:1602
static BOOL MONTHCAL_SetUnicodeFormat(MONTHCAL_INFO *infoPtr, BOOL isUnicode)
Definition: monthcal.c:2871
int MONTHCAL_CalculateDayOfWeek(SYSTEMTIME *date, BOOL inplace)
Definition: monthcal.c:470
#define GDTR_MAX
Definition: commctrl.h:4453
#define MCM_GETFIRSTDAYOFWEEK
Definition: commctrl.h:4256
HTHEME WINAPI GetWindowTheme(HWND hwnd)
Definition: system.c:851
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
void MONTHCAL_Register(void)
Definition: monthcal.c:3037
COLORREF colors[MCSC_TRAILINGTEXT+1]
Definition: monthcal.c:107
static INT MONTHCAL_StyleChanged(MONTHCAL_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
Definition: monthcal.c:2717
#define index(s, c)
Definition: various.h:29
#define UDN_DELTAPOS
Definition: commctrl.h:2165
HWND WINAPI CreateWindowExW(_In_ DWORD dwExStyle, _In_opt_ LPCWSTR lpClassName, _In_opt_ LPCWSTR lpWindowName, _In_ DWORD dwStyle, _In_ int X, _In_ int Y, _In_ int nWidth, _In_ int nHeight, _In_opt_ HWND hWndParent, _In_opt_ HMENU hMenu, _In_opt_ HINSTANCE hInstance, _In_opt_ LPVOID lpParam)
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean flag
Definition: glfuncs.h:52
HDC hdc
Definition: main.c:9
static void MONTHCAL_DrawDay(const MONTHCAL_INFO *infoPtr, HDC hdc, const SYSTEMTIME *st, int bold, const PAINTSTRUCT *ps)
Definition: monthcal.c:786
static void MONTHCAL_GetMinDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
Definition: monthcal.c:511
#define MCSC_BACKGROUND
Definition: commctrl.h:4203
#define GDTR_MIN
Definition: commctrl.h:4452
LONG MONTHCAL_CompareSystemTime(const SYSTEMTIME *first, const SYSTEMTIME *second)
Definition: monthcal.c:305
static int state
Definition: maze.c:121
MONTHDAYSTATE * monthdayState
Definition: monthcal.c:124
static LRESULT MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, LPARAM lParam)
Definition: monthcal.c:2366
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static void MONTHCAL_PaintTitle(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
Definition: monthcal.c:867
#define MCHT_TITLEMONTH
Definition: commctrl.h:4242
#define WM_APP
Definition: eventvwr.h:70
static LONG MONTHCAL_CompareDate(const SYSTEMTIME *first, const SYSTEMTIME *second)
Definition: monthcal.c:327
BOOL WINAPI SetRectEmpty(_Out_ LPRECT)
Definition: time.h:76
GLenum src
Definition: glext.h:6340
HWND hwndFrom
Definition: winuser.h:3132
uint32_t DWORD_PTR
Definition: typedefs.h:63
static BOOL MONTHCAL_ValidateDate(const SYSTEMTIME *time)
Definition: monthcal.c:251
BOOL WINAPI IntersectRect(_Out_ LPRECT, _In_ LPCRECT, _In_ LPCRECT)
#define LOCALE_IFIRSTDAYOFWEEK
Definition: winnls.h:75
#define WM_USER
Definition: winuser.h:1877
#define DLGC_WANTALLKEYS
Definition: winuser.h:2587
#define GWLP_WNDPROC
Definition: treelist.c:66
INT WINAPI GetDateFormatW(LCID lcid, DWORD dwFlags, const SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpDateStr, INT cchOut)
Definition: lcformat.c:979
GLenum GLint * range
Definition: glext.h:7539
CALENDAR_INFO * calendars
Definition: monthcal.c:145
#define LOCALE_IFIRSTWEEKOFYEAR
Definition: winnls.h:76
static LRESULT MONTHCAL_LButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam)
Definition: monthcal.c:2275
BOOL isUnicode
Definition: monthcal.c:122
static void MONTHCAL_Circle(const MONTHCAL_INFO *infoPtr, HDC hdc, const RECT *r)
Definition: monthcal.c:759
HCURSOR hCursor
Definition: winuser.h:3157
#define MCS_NOTODAY
Definition: commctrl.h:4307
LRESULT(CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM)
Definition: winuser.h:2881
#define ERR(fmt,...)
Definition: debug.h:109
#define GWL_STYLE
Definition: winuser.h:846
#define UDM_SETBUDDY
Definition: commctrl.h:2141
COLORREF WINAPI SetTextColor(_In_ HDC, _In_ COLORREF)
Definition: text.c:888
#define MCSC_TITLEBK
Definition: commctrl.h:4205
WORD wDay
Definition: winbase.h:880
void redraw(int x, int y, int cx, int cy)
Definition: qtewin.cpp:1248
static BOOL MONTHCAL_GetUnicodeFormat(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:2879
int WINAPI GetObjectW(_In_ HANDLE h, _In_ int c, _Out_writes_bytes_opt_(c) LPVOID pv)
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
#define DT_SINGLELINE
Definition: winuser.h:540
int iDelta
Definition: commctrl.h:2162
HWND WINAPI GetParent(_In_ HWND)
CachedBrush
Definition: monthcal.c:81
COLORREF clrGrayText
Definition: comctl32.h:171
SYSTEMTIME st
Definition: commctrl.h:4221
SYSTEMTIME stStart
Definition: commctrl.h:4291
HWND WINAPI SetCapture(_In_ HWND hWnd)
static void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to)
Definition: monthcal.c:268
RECT titlebtnnext
Definition: monthcal.c:137
#define IDM_GOTODAY
Definition: comctl32.h:78
BOOL WINAPI SystemTimeToFileTime(IN CONST SYSTEMTIME *lpSystemTime, OUT LPFILETIME lpFileTime)
Definition: time.c:158
static unsigned __int64 next
Definition: rand_nt.c:6
#define FW_BOLD
Definition: wingdi.h:377
static BOOL MONTHCAL_GetDayRect(const MONTHCAL_INFO *infoPtr, const SYSTEMTIME *date, RECT *r, INT calIdx)
Definition: monthcal.c:637
HFONT hFont
Definition: monthcal.c:111
HMODULE COMCTL32_hModule
Definition: commctrl.c:79
struct MONTHCAL_INFO * LPMONTHCAL_INFO
RECT todayrect
Definition: monthcal.c:139
#define ARRAY_SIZE(a)
Definition: main.h:24
__u16 date
Definition: mkdosfs.c:366
HBRUSH hbrBackground
Definition: winuser.h:3158
static void MONTHCAL_PaintFocusAndCircle(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
Definition: monthcal.c:1095
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_LBUTTONUP
Definition: winuser.h:1759
static void MONTHCAL_PaintWeeknumbers(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
Definition: monthcal.c:950
WORD wHour
Definition: winbase.h:881
static LRESULT MONTHCAL_GetMaxSelCount(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:1618
static const struct newhuff ht[]
Definition: huffman.h:296
#define GMR_VISIBLE
Definition: commctrl.h:4311
#define MCS_NOTODAYCIRCLE
Definition: commctrl.h:4306
int height_increment
Definition: monthcal.c:114
DWORD styleNew
Definition: winuser.h:3668
#define UDM_SETPOS
Definition: commctrl.h:2139
struct _CALENDAR_INFO CALENDAR_INFO
static LRESULT MONTHCAL_SetToday(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *today)
Definition: monthcal.c:1761
unsigned int UINT
Definition: ndis.h:50
#define WM_MOUSEMOVE
Definition: winuser.h:1757
HBRUSH WINAPI CreateSolidBrush(_In_ COLORREF)
#define MCM_GETMAXSELCOUNT
Definition: commctrl.h:4184
#define MCSC_TRAILINGTEXT
Definition: commctrl.h:4208
static const SYSTEMTIME st_null
Definition: monthcal.c:152
static void MONTHCAL_NotifySelect(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:191
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLint dx
Definition: linetemp.h:97
#define DFC_SCROLL
Definition: winuser.h:475
void MONTHCAL_Unregister(void)
Definition: monthcal.c:3055
#define WM_SETFONT
Definition: winuser.h:1632
DWORD styleOld
Definition: winuser.h:3667
static void MONTHCAL_GetMonth(SYSTEMTIME *date, INT months)
Definition: monthcal.c:486
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
HMENU WINAPI CreatePopupMenu(void)
Definition: menu.c:846
static LRESULT MONTHCAL_Timer(MONTHCAL_INFO *infoPtr, WPARAM id)
Definition: monthcal.c:2332
static LRESULT MONTHCAL_SetFont(MONTHCAL_INFO *infoPtr, HFONT hFont, BOOL redraw)
Definition: monthcal.c:2686
HBRUSH brushes[BrushLast]
Definition: monthcal.c:108
#define MCN_GETDAYSTATE
Definition: commctrl.h:4297
static BOOL MONTHCAL_IsDateEqual(const SYSTEMTIME *first, const SYSTEMTIME *second)
Definition: monthcal.c:244
static LRESULT MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
Definition: monthcal.c:1555
static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc, const SYSTEMTIME *date)
Definition: monthcal.c:777
BOOL WINAPI PtInRect(_In_ LPCRECT, _In_ POINT)
#define MCHITTESTINFO_V1_SIZE
Definition: commctrl.h:4230
#define MCHT_CALENDARDAY
Definition: commctrl.h:4251
#define IDC_ARROW
Definition: winuser.h:682
BOOL WINAPI ReleaseCapture(void)
Definition: message.c:2888
static void MONTHCAL_GetDayRectI(const MONTHCAL_INFO *infoPtr, RECT *r, INT col, INT row, INT calIdx)
Definition: monthcal.c:624
static LONG MONTHCAL_CompareMonths(const SYSTEMTIME *first, const SYSTEMTIME *second)
Definition: monthcal.c:315
static void MONTHCAL_EditYear(MONTHCAL_INFO *infoPtr, INT calIdx)
Definition: monthcal.c:2119
#define MC_PREVNEXTMONTHTIMER
Definition: monthcal.c:66
#define WM_CREATE
Definition: winuser.h:1590
#define MCS_NOTRAILINGDATES
Definition: commctrl.h:4308
#define MCM_GETMONTHDELTA
Definition: commctrl.h:4262
LRESULT WINAPI CallWindowProcW(_In_ WNDPROC, _In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define MCM_GETSELRANGE
Definition: commctrl.h:4188
#define MCM_SETMONTHDELTA
Definition: commctrl.h:4264
static int get_localized_dayname(const MONTHCAL_INFO *infoPtr, unsigned int day, WCHAR *buff, unsigned int count)
Definition: monthcal.c:1158
#define UDS_SETBUDDYINT
Definition: commctrl.h:2128
#define HIWORD(l)
Definition: typedefs.h:246
BOOL WINAPI IsWindowVisible(_In_ HWND)
RECT text_rect
Definition: sndrec32.cpp:77
LONG bottom
Definition: windef.h:309
BOOL COMCTL32_IsReflectedMessage(UINT uMsg) DECLSPEC_HIDDEN
Definition: commctrl.c:1748
static LRESULT MONTHCAL_GetRange(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *range)
Definition: monthcal.c:1516
#define DT_CENTER
Definition: winuser.h:527
#define MCM_GETCOLOR
Definition: commctrl.h:4200
#define MC_SEL_LBUTUP
Definition: monthcal.c:57
static char * dest
Definition: rtl.c:135
static INT MONTHCAL_GetCalCount(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:165
static int MONTHCAL_GetDayFromPos(const MONTHCAL_INFO *infoPtr, POINT pt, INT calIdx)
Definition: monthcal.c:565
#define SetWindowLongPtrW
Definition: winuser.h:5321
#define MC_SEL_LBUTDOWN
Definition: monthcal.c:58
LONG lfWeight
Definition: dimm.idl:63
#define WM_ERASEBKGND
Definition: winuser.h:1607
#define WM_SETFOCUS
Definition: winuser.h:1595
int month[12]
Definition: systime.c:13
#define PRF_CLIENT
Definition: winuser.h:2500
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define DFCS_SCROLLLEFT
Definition: winuser.h:491
static LRESULT MONTHCAL_GetFirstDayOfWeek(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:1377
#define MCM_GETMONTHRANGE
Definition: commctrl.h:4192
LONG_PTR LRESULT
Definition: windef.h:209
CardRegion * from
Definition: spigame.cpp:19
#define UPDOWN_CLASSW
Definition: commctrl.h:2115
int WINAPI FillRect(HDC, LPCRECT, HBRUSH)
CachedPen
Definition: monthcal.c:74
Arabic default style
Definition: afstyles.h:93
COLORREF clrWindow
Definition: comctl32.h:169
#define MCM_GETMAXTODAYWIDTH
Definition: commctrl.h:4266
#define WS_VISIBLE
Definition: pedump.c:620
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
LONG cy
Definition: windef.h:335
DWORD MONTHDAYSTATE
Definition: commctrl.h:4176
LPARAM lParam
Definition: combotst.c:139
BOOL WINAPI TrackPopupMenu(_In_ HMENU, _In_ UINT, _In_ int, _In_ int, _Reserved_ int, _In_ HWND, _Reserved_ LPCRECT)
#define MCHT_CALENDARDATEPREV
Definition: commctrl.h:4250
static char title[]
Definition: ps.c:92
#define LOWORD(l)
Definition: pedump.c:82
VOID COMCTL32_RefreshSysColors(void) DECLSPEC_HIDDEN
Definition: commctrl.c:1586
static unsigned char buff[32768]
Definition: fatten.c:17
struct _ULARGE_INTEGER::@3769 u
#define GWLP_ID
Definition: winuser.h:854
#define DLGC_WANTARROWS
Definition: winuser.h:2585
HGDIOBJ WINAPI GetCurrentObject(_In_ HDC, _In_ UINT)
Definition: dc.c:439
HRESULT WINAPI CloseThemeData(HTHEME hTheme)
Definition: system.c:950
DWORD dwLowDateTime
Definition: mapidefs.h:65
BOOL WINAPI GetTextExtentPoint32W(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpString, _In_ int c, _Out_ LPSIZE psizl)
#define WM_NOTIFY
Definition: richedit.h:61
static LRESULT MONTHCAL_Destroy(MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:2830
SYSTEMTIME maxDate
Definition: monthcal.c:135
static LRESULT MONTHCAL_SetFocus(const MONTHCAL_INFO *infoPtr)
Definition: monthcal.c:2478
#define MCHT_TITLEYEAR
Definition: commctrl.h:4243
nav_direction
Definition: monthcal.c:158
WINE_UNICODE_INLINE int atoiW(const WCHAR *str)
Definition: unicode.h:315
static void MONTHCAL_PaintCalendar(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
Definition: monthcal.c:1171
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
INT WINAPI DrawTextW(HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags)
Definition: defwnd.c:17
static BOOL heap_free(void *mem)
Definition: appwiz.h:75
#define MC_PREVNEXTMONTHDELAY
Definition: monthcal.c:61
#define MCM_SETTODAY
Definition: commctrl.h:4210
static BOOL MONTHCAL_ValidateTime(const SYSTEMTIME *time)
Definition: monthcal.c:446