* Copyright 1999 Chris Morgan <cmorgan@wpi.edu> and
* James Abbatiello <abbeyj@wpi.edu>
* Copyright 2000 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
- * Copyright 2009 Nikolay Sivov
+ * Copyright 2009-2011 Nikolay Sivov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*
* TODO:
* -- MCM_[GS]ETUNICODEFORMAT
- * -- MONTHCAL_GetMonthRange
* -- handle resources better (doesn't work now);
* -- take care of internationalization.
* -- keyboard handling.
#define MC_PREVPRESSED 4 /* Prev month button pressed */
#define MC_NEXTPRESSED 8 /* Next month button pressed */
#define MC_PREVNEXTMONTHDELAY 350 /* when continuously pressing `next/prev
- month', wait 500 ms before going
+ month', wait 350 ms before going
to the next/prev month */
#define MC_TODAYUPDATEDELAY 120000 /* time between today check for update (2 min) */
/* convert from days to 100 nanoseconds unit - used as FILETIME unit */
#define DAYSTO100NSECS(days) (((ULONGLONG)(days))*24*60*60*10000000)
+enum CachedPen
+{
+ PenRed = 0,
+ PenText,
+ PenLast
+};
+
+enum CachedBrush
+{
+ BrushTitle = 0,
+ BrushMonth,
+ BrushBackground,
+ BrushLast
+};
+
+/* single calendar data */
+typedef struct _CALENDAR_INFO
+{
+ RECT title; /* rect for the header above the calendar */
+ RECT titlemonth; /* the 'month name' text in the header */
+ RECT titleyear; /* the 'year number' text in the header */
+ RECT wdays; /* week days at top */
+ RECT days; /* calendar area */
+ RECT weeknums; /* week numbers at left side */
+
+ SYSTEMTIME month;/* contains calendar main month/year */
+} CALENDAR_INFO;
+
typedef struct
{
HWND hwndSelf;
DWORD dwStyle; /* cached GWL_STYLE */
- COLORREF bk;
- COLORREF txt;
- COLORREF titlebk;
- COLORREF titletxt;
- COLORREF monthbk;
- COLORREF trailingtxt;
+
+ COLORREF colors[MCSC_TRAILINGTEXT+1];
+ HBRUSH brushes[BrushLast];
+ HPEN pens[PenLast];
+
HFONT hFont;
HFONT hBoldFont;
int textHeight;
int textWidth;
int height_increment;
int width_increment;
- int firstDayplace; /* place of the first day of the current month */
INT delta; /* scroll rate; # of months that the */
/* control moves when user clicks a scroll button */
int visible; /* # of months visible */
stored in SYSTEMTIME format */
BOOL firstDaySet; /* first week day differs from locale defined */
+ BOOL isUnicode; /* value set with MCM_SETUNICODE format */
+
int monthRange;
MONTHDAYSTATE *monthdayState;
SYSTEMTIME todaysDate;
int status; /* See MC_SEL flags */
SYSTEMTIME firstSel; /* first selected day */
INT maxSelCount;
- SYSTEMTIME minSel;
+ SYSTEMTIME minSel; /* contains single selection when used without MCS_MULTISELECT */
SYSTEMTIME maxSel;
- SYSTEMTIME curSel; /* contains currently selected year, month and day */
SYSTEMTIME focusedSel; /* date currently focused with mouse movement */
DWORD rangeValid;
SYSTEMTIME minDate;
SYSTEMTIME maxDate;
- RECT title; /* rect for the header above the calendar */
RECT titlebtnnext; /* the `next month' button in the header */
RECT titlebtnprev; /* the `prev month' button in the header */
- RECT titlemonth; /* the `month name' txt in the header */
- RECT titleyear; /* the `year number' txt in the header */
- RECT wdays; /* week days at top */
- RECT days; /* calendar area */
- RECT weeknums; /* week numbers at left side */
RECT todayrect; /* `today: xx/xx/xx' text rect */
HWND hwndNotify; /* Window to receive the notifications */
HWND hWndYearEdit; /* Window Handle of edit box to handle years */
HWND hWndYearUpDown;/* Window Handle of updown box to handle years */
WNDPROC EditWndProc; /* original Edit window procedure */
+
+ CALENDAR_INFO *calendars;
+ INT cal_num;
} MONTHCAL_INFO, *LPMONTHCAL_INFO;
static const WCHAR themeClass[] = { 'S','c','r','o','l','l','b','a','r',0 };
static const SYSTEMTIME max_allowed_date = { .wYear = 9999, .wMonth = 12, .wDay = 31 };
static const SYSTEMTIME min_allowed_date = { .wYear = 1752, .wMonth = 9, .wDay = 14 };
-
-#define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)GetWindowLongPtrW(hwnd, 0))
+/* Prev/Next buttons */
+enum nav_direction
+{
+ DIRECTION_BACKWARD,
+ DIRECTION_FORWARD
+};
/* helper functions */
/* january is 1, december is 12 */
int MONTHCAL_MonthLength(int month, int year)
{
- const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
+ const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/* Wrap around, this eases handling. Getting length only we shouldn't care
about year change here cause January and December have
the same day quantity */
return TRUE;
}
+/* Copies timestamp part only.
+ *
+ * PARAMETERS
+ *
+ * [I] from : source date
+ * [O] to : dest date
+ */
+static void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to)
+{
+ to->wHour = from->wHour;
+ to->wMinute = from->wMinute;
+ to->wSecond = from->wSecond;
+}
+
+/* Copies date part only.
+ *
+ * PARAMETERS
+ *
+ * [I] from : source date
+ * [O] to : dest date
+ */
+static void MONTHCAL_CopyDate(const SYSTEMTIME *from, SYSTEMTIME *to)
+{
+ to->wYear = from->wYear;
+ to->wMonth = from->wMonth;
+ to->wDay = from->wDay;
+ to->wDayOfWeek = from->wDayOfWeek;
+}
+
/* Compares two dates in SYSTEMTIME format
*
* PARAMETERS
return CompareFileTime(&ft_first, &ft_second);
}
+static LONG MONTHCAL_CompareMonths(const SYSTEMTIME *first, const SYSTEMTIME *second)
+{
+ SYSTEMTIME st_first, st_second;
+
+ st_first = st_second = st_null;
+ MONTHCAL_CopyDate(first, &st_first);
+ MONTHCAL_CopyDate(second, &st_second);
+ st_first.wDay = st_second.wDay = 1;
+
+ return MONTHCAL_CompareSystemTime(&st_first, &st_second);
+}
+
+static LONG MONTHCAL_CompareDate(const SYSTEMTIME *first, const SYSTEMTIME *second)
+{
+ SYSTEMTIME st_first, st_second;
+
+ st_first = st_second = st_null;
+ MONTHCAL_CopyDate(first, &st_first);
+ MONTHCAL_CopyDate(second, &st_second);
+
+ return MONTHCAL_CompareSystemTime(&st_first, &st_second);
+}
+
/* Checks largest possible date range and configured one
*
* PARAMETERS
SystemTimeToFileTime(range0, &ft_range0);
SystemTimeToFileTime(range1, &ft_range1);
- ul_range0.LowPart = ft_range0.dwLowDateTime;
- ul_range0.HighPart = ft_range0.dwHighDateTime;
- ul_range1.LowPart = ft_range1.dwLowDateTime;
- ul_range1.HighPart = ft_range1.dwHighDateTime;
+ ul_range0.u.LowPart = ft_range0.dwLowDateTime;
+ ul_range0.u.HighPart = ft_range0.dwHighDateTime;
+ ul_range1.u.LowPart = ft_range1.dwLowDateTime;
+ ul_range1.u.HighPart = ft_range1.dwHighDateTime;
cmp = CompareFileTime(&ft_range0, &ft_range1);
else
ul_range0.QuadPart = ul_range1.QuadPart - DAYSTO100NSECS(infoPtr->maxSelCount - 1);
- ft_range0.dwLowDateTime = ul_range0.LowPart;
- ft_range0.dwHighDateTime = ul_range0.HighPart;
+ ft_range0.dwLowDateTime = ul_range0.u.LowPart;
+ ft_range0.dwHighDateTime = ul_range0.u.HighPart;
FileTimeToSystemTime(&ft_range0, adjust);
}
return TRUE;
}
-/* Copies timestamp part only.
- *
- * PARAMETERS
- *
- * [I] from : source date
- * [O] to : dest date
- */
-static void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to)
-{
- to->wHour = from->wHour;
- to->wMinute = from->wMinute;
- to->wSecond = from->wSecond;
-}
-
-/* Copies date part only.
- *
- * PARAMETERS
- *
- * [I] from : source date
- * [O] to : dest date
- */
-static void MONTHCAL_CopyDate(const SYSTEMTIME *from, SYSTEMTIME *to)
-{
- to->wYear = from->wYear;
- to->wMonth = from->wMonth;
- to->wDay = from->wDay;
- to->wDayOfWeek = from->wDayOfWeek;
-}
-
/* Note:Depending on DST, this may be offset by a day.
Need to find out if we're on a DST place & adjust the clock accordingly.
Above function assumes we have a valid data.
/* Returns the day in the week
*
* PARAMETERS
- * [i] day : day of month [1, 31]
- * [I] month : month number [1, 12]
- * [I] year : year value
+ * [i] date : input date
+ * [I] inplace : set calculated value back to date structure
*
* RETURN VALUE
* day of week in SYSTEMTIME format: (0 == sunday,..., 6 == saturday)
*/
-int MONTHCAL_CalculateDayOfWeek(WORD day, WORD month, WORD year)
+int MONTHCAL_CalculateDayOfWeek(SYSTEMTIME *date, BOOL inplace)
{
+ SYSTEMTIME st = st_null;
FILETIME ft;
- SYSTEMTIME st;
- st.wYear = year;
- st.wMonth = month;
- st.wDay = day;
- st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
+ MONTHCAL_CopyDate(date, &st);
SystemTimeToFileTime(&st, &ft);
FileTimeToSystemTime(&ft, &st);
+ if (inplace) date->wDayOfWeek = st.wDayOfWeek;
+
return st.wDayOfWeek;
}
+/* add/subtract 'months' from date */
+static inline void MONTHCAL_GetMonth(SYSTEMTIME *date, INT months)
+{
+ INT length, m = date->wMonth + months;
+
+ date->wYear += m > 0 ? (m - 1) / 12 : m / 12 - 1;
+ date->wMonth = m > 0 ? (m - 1) % 12 + 1 : 12 + m % 12;
+ /* fix moving from last day in a month */
+ length = MONTHCAL_MonthLength(date->wMonth, date->wYear);
+ if(date->wDay > length) date->wDay = length;
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
+}
+
/* properly updates date to point on next month */
static inline void MONTHCAL_GetNextMonth(SYSTEMTIME *date)
{
- if(++date->wMonth > 12)
- {
- date->wMonth = 1;
- date->wYear++;
- }
- date->wDayOfWeek = MONTHCAL_CalculateDayOfWeek(date->wDay, date->wMonth,
- date->wYear);
+ return MONTHCAL_GetMonth(date, 1);
}
/* properly updates date to point on prev month */
static inline void MONTHCAL_GetPrevMonth(SYSTEMTIME *date)
{
- if(--date->wMonth < 1)
- {
- date->wMonth = 12;
- date->wYear--;
- }
- date->wDayOfWeek = MONTHCAL_CalculateDayOfWeek(date->wDay, date->wMonth,
- date->wYear);
+ return MONTHCAL_GetMonth(date, -1);
}
/* Returns full date for a first currently visible day */
static void MONTHCAL_GetMinDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
{
- int firstDay;
+ /* zero indexed calendar has the earliest date */
+ SYSTEMTIME st_first = infoPtr->calendars[0].month;
+ INT firstDay;
- firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+ st_first.wDay = 1;
+ firstDay = MONTHCAL_CalculateDayOfWeek(&st_first, FALSE);
- *date = infoPtr->curSel;
+ *date = infoPtr->calendars[0].month;
MONTHCAL_GetPrevMonth(date);
date->wDay = MONTHCAL_MonthLength(date->wMonth, date->wYear) +
date->wDay -= 7;
/* fix day of week */
- date->wDayOfWeek = MONTHCAL_CalculateDayOfWeek(date->wDay, date->wMonth,
- date->wYear);
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
}
/* Returns full date for a last currently visible day */
static void MONTHCAL_GetMaxDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
{
- SYSTEMTIME st;
+ /* the latest date is in latest calendar */
+ SYSTEMTIME st, lt_month = infoPtr->calendars[infoPtr->cal_num-1].month;
- *date = infoPtr->curSel;
+ *date = lt_month;
MONTHCAL_GetNextMonth(date);
MONTHCAL_GetMinDate(infoPtr, &st);
/* Use month length to get max day. 42 means max day count in calendar area */
date->wDay = 42 - (MONTHCAL_MonthLength(st.wMonth, st.wYear) - st.wDay + 1) -
- MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+ MONTHCAL_MonthLength(lt_month.wMonth, lt_month.wYear);
/* fix day of week */
- date->wDayOfWeek = MONTHCAL_CalculateDayOfWeek(date->wDay, date->wMonth,
- date->wYear);
+ MONTHCAL_CalculateDayOfWeek(date, TRUE);
}
/* From a given point, calculate the row (weekpos), column(daypos)
and day in the calendar. day== 0 mean the last day of tha last month
*/
static int MONTHCAL_CalcDayFromPos(const MONTHCAL_INFO *infoPtr, int x, int y,
- int *daypos,int *weekpos)
+ int *daypos, int *weekpos)
{
int retval, firstDay;
RECT rcClient;
+ SYSTEMTIME st = infoPtr->minSel;
GetClientRect(infoPtr->hwndSelf, &rcClient);
if (x > rcClient.right)
x = rcClient.right;
+ *daypos = (x - infoPtr->calendars[0].days.left ) / infoPtr->width_increment;
+ *weekpos = (y - infoPtr->calendars[0].days.top ) / infoPtr->height_increment;
- *daypos = (x - infoPtr->days.left ) / infoPtr->width_increment;
- *weekpos = (y - infoPtr->days.top ) / infoPtr->height_increment;
-
- firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->curSel.wMonth, infoPtr->curSel.wYear)+6 - infoPtr->firstDay)%7;
+ st.wDay = 1;
+ firstDay = (MONTHCAL_CalculateDayOfWeek(&st, FALSE) + 6 - infoPtr->firstDay) % 7;
retval = *daypos + (7 * *weekpos) - firstDay;
return retval;
}
-/* day is the day of the month, 1 == 1st day of the month */
-/* sets x and y to be the position of the day */
-/* x == day, y == week where(0,0) == firstDay, 1st week */
-static void MONTHCAL_CalcDayXY(const MONTHCAL_INFO *infoPtr, int day, int month,
- int *x, int *y)
+/* Sets the RECT struct r to the rectangle around the date
+ *
+ * PARAMETERS
+ *
+ * [I] infoPtr : pointer to control data
+ * [I] date : date value
+ * [O] x : day column (zero based)
+ * [O] y : week column (zero based)
+ */
+static void MONTHCAL_CalcDayXY(const MONTHCAL_INFO *infoPtr,
+ const SYSTEMTIME *date, INT *x, INT *y)
{
- int firstDay, prevMonth;
+ SYSTEMTIME st = infoPtr->minSel;
+ LONG cmp;
+ int first;
- firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->curSel.wMonth, infoPtr->curSel.wYear) +6 - infoPtr->firstDay)%7;
+ st.wDay = 1;
+ first = (MONTHCAL_CalculateDayOfWeek(&st, FALSE) + 6 - infoPtr->firstDay) % 7;
- if(month==infoPtr->curSel.wMonth) {
- *x = (day + firstDay) % 7;
- *y = (day + firstDay - *x) / 7;
- return;
- }
- if(month < infoPtr->curSel.wMonth) {
- prevMonth = month - 1;
- if(prevMonth==0)
- prevMonth = 12;
+ cmp = MONTHCAL_CompareMonths(date, &infoPtr->minSel);
- *x = (MONTHCAL_MonthLength(prevMonth, infoPtr->curSel.wYear) - firstDay) % 7;
+ /* previous month */
+ if(cmp == -1) {
+ *x = (first - MONTHCAL_MonthLength(date->wMonth, infoPtr->minSel.wYear) + date->wDay) % 7;
*y = 0;
return;
}
- *y = MONTHCAL_MonthLength(month, infoPtr->curSel.wYear - 1) / 7;
- *x = (day + firstDay + MONTHCAL_MonthLength(month,
- infoPtr->curSel.wYear)) % 7;
+ /* next month calculation is same as for current,
+ just add current month length */
+ if(cmp == 1) {
+ first += MONTHCAL_MonthLength(infoPtr->minSel.wMonth, infoPtr->minSel.wYear);
+ }
+
+ *x = (date->wDay + first) % 7;
+ *y = (date->wDay + first - *x) / 7;
}
/* x: column(day), y: row(week) */
-static void MONTHCAL_CalcDayRect(const MONTHCAL_INFO *infoPtr, RECT *r, int x, int y)
+static inline void MONTHCAL_CalcDayRect(const MONTHCAL_INFO *infoPtr, RECT *r, int x, int y)
{
- r->left = infoPtr->days.left + x * infoPtr->width_increment;
+ r->left = infoPtr->calendars[0].days.left + x * infoPtr->width_increment;
r->right = r->left + infoPtr->width_increment;
- r->top = infoPtr->days.top + y * infoPtr->height_increment;
+ r->top = infoPtr->calendars[0].days.top + y * infoPtr->height_increment;
r->bottom = r->top + infoPtr->textHeight;
}
-/* sets the RECT struct r to the rectangle around the day and month */
-/* day is the day value of the month(1 == 1st), month is the month */
-/* value(january == 1, december == 12) */
+/* Sets the RECT struct r to the rectangle around the date */
static inline void MONTHCAL_CalcPosFromDay(const MONTHCAL_INFO *infoPtr,
- int day, int month, RECT *r)
+ const SYSTEMTIME *date, RECT *r)
{
int x, y;
- MONTHCAL_CalcDayXY(infoPtr, day, month, &x, &y);
+ MONTHCAL_CalcDayXY(infoPtr, date, &x, &y);
MONTHCAL_CalcDayRect(infoPtr, r, x, y);
}
if(MONTHCAL_IsDateEqual(&infoPtr->focusedSel, st)) return FALSE;
/* invalidate old focused day */
- MONTHCAL_CalcPosFromDay(infoPtr, infoPtr->focusedSel.wDay,
- infoPtr->focusedSel.wMonth, &r);
+ MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->focusedSel, &r);
InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
infoPtr->focusedSel = *st;
}
- MONTHCAL_CalcPosFromDay(infoPtr, infoPtr->focusedSel.wDay,
- infoPtr->focusedSel.wMonth, &r);
+ MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->focusedSel, &r);
if(!st && MONTHCAL_ValidateDate(&infoPtr->focusedSel))
infoPtr->focusedSel = st_null;
return TRUE;
}
-/* day is the day in the month(1 == 1st of the month) */
-/* month is the month value(1 == january, 12 == december) */
-static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month)
+/* draw today boundary box for specified rectangle */
+static void MONTHCAL_Circle(const MONTHCAL_INFO *infoPtr, HDC hdc, const RECT *r)
{
- HPEN hRedPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
- HPEN hOldPen2 = SelectObject(hdc, hRedPen);
- HBRUSH hOldBrush;
- RECT day_rect;
+ HPEN old_pen = SelectObject(hdc, infoPtr->pens[PenRed]);
+ HBRUSH old_brush;
- MONTHCAL_CalcPosFromDay(infoPtr, day, month, &day_rect);
+ old_brush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
+ Rectangle(hdc, r->left, r->top, r->right, r->bottom);
- hOldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
- Rectangle(hdc, day_rect.left, day_rect.top, day_rect.right, day_rect.bottom);
+ SelectObject(hdc, old_brush);
+ SelectObject(hdc, old_pen);
+}
- SelectObject(hdc, hOldBrush);
- DeleteObject(hRedPen);
- SelectObject(hdc, hOldPen2);
+/* Draw today day mark rectangle
+ *
+ * [I] hdc : context to draw in
+ * [I] date : day to mark with rectangle
+ *
+ */
+static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc,
+ const SYSTEMTIME *date)
+{
+ RECT day_rect;
+ MONTHCAL_CalcPosFromDay(infoPtr, date, &day_rect);
+ MONTHCAL_Circle(infoPtr, hdc, &day_rect);
}
-static void MONTHCAL_DrawDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month,
- int x, int y, int bold)
+static void MONTHCAL_DrawDay(const MONTHCAL_INFO *infoPtr, HDC hdc, const SYSTEMTIME *st,
+ int bold, const PAINTSTRUCT *ps)
{
static const WCHAR fmtW[] = { '%','d',0 };
WCHAR buf[10];
- RECT r;
- static BOOL haveBoldFont, haveSelectedDay = FALSE;
- HBRUSH hbr;
+ RECT r, r_temp;
COLORREF oldCol = 0;
- COLORREF oldBk = 0;
+ COLORREF oldBk = 0;
+ INT old_bkmode, selection;
- wsprintfW(buf, fmtW, day);
+ /* no need to check styles: when selection is not valid, it is set to zero.
+ 1 < day < 31, so everything is OK */
+ MONTHCAL_CalcPosFromDay(infoPtr, st, &r);
+ if(!IntersectRect(&r_temp, &(ps->rcPaint), &r)) return;
-/* No need to check styles: when selection is not valid, it is set to zero.
- * 1<day<31, so everything is OK.
- */
-
- MONTHCAL_CalcDayRect(infoPtr, &r, x, y);
-
- if((day>=infoPtr->minSel.wDay) && (day<=infoPtr->maxSel.wDay)
- && (month == infoPtr->curSel.wMonth)) {
- RECT r2;
+ if ((MONTHCAL_CompareDate(st, &infoPtr->minSel) >= 0) &&
+ (MONTHCAL_CompareDate(st, &infoPtr->maxSel) <= 0))
+ {
- TRACE("%d %d %d\n",day, infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
+ TRACE("%d %d %d\n", st->wDay, infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
TRACE("%s\n", wine_dbgstr_rect(&r));
- oldCol = SetTextColor(hdc, infoPtr->monthbk);
- oldBk = SetBkColor(hdc, infoPtr->trailingtxt);
- hbr = GetSysColorBrush(COLOR_HIGHLIGHT);
- FillRect(hdc, &r, hbr);
+ oldCol = SetTextColor(hdc, infoPtr->colors[MCSC_MONTHBK]);
+ oldBk = SetBkColor(hdc, infoPtr->colors[MCSC_TRAILINGTEXT]);
+ FillRect(hdc, &r, infoPtr->brushes[BrushTitle]);
- /* FIXME: this may need to be changed now b/c of the other
- drawing changes 11/3/99 CMM */
- r2.left = r.left - 0.25 * infoPtr->textWidth;
- r2.top = r.top;
- r2.right = r.left + 0.5 * infoPtr->textWidth;
- r2.bottom = r.bottom;
- if(haveSelectedDay) FillRect(hdc, &r2, hbr);
- haveSelectedDay = TRUE;
- } else {
- haveSelectedDay = FALSE;
+ selection = 1;
}
+ else
+ selection = 0;
- /* need to add some code for multiple selections */
-
- if((bold) &&(!haveBoldFont)) {
- SelectObject(hdc, infoPtr->hBoldFont);
- haveBoldFont = TRUE;
- }
- if((!bold) &&(haveBoldFont)) {
- SelectObject(hdc, infoPtr->hFont);
- haveBoldFont = FALSE;
- }
+ SelectObject(hdc, bold ? infoPtr->hBoldFont : infoPtr->hFont);
- SetBkMode(hdc,TRANSPARENT);
+ old_bkmode = SetBkMode(hdc, TRANSPARENT);
+ wsprintfW(buf, fmtW, st->wDay);
DrawTextW(hdc, buf, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
+ SetBkMode(hdc, old_bkmode);
- if(haveSelectedDay) {
+ if (selection)
+ {
SetTextColor(hdc, oldCol);
SetBkColor(hdc, oldBk);
}
}
-static void paint_button (MONTHCAL_INFO *infoPtr, HDC hdc, BOOL btnNext)
+static void MONTHCAL_PaintButton(MONTHCAL_INFO *infoPtr, HDC hdc, enum nav_direction button)
{
HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
- RECT *r = btnNext ? &infoPtr->titlebtnnext : &infoPtr->titlebtnprev;
- BOOL pressed = btnNext ? (infoPtr->status & MC_NEXTPRESSED) :
- (infoPtr->status & MC_PREVPRESSED);
+ RECT *r = button == DIRECTION_FORWARD ? &infoPtr->titlebtnnext : &infoPtr->titlebtnprev;
+ BOOL pressed = button == DIRECTION_FORWARD ? infoPtr->status & MC_NEXTPRESSED :
+ infoPtr->status & MC_PREVPRESSED;
if (theme)
{
static const int states[] = {
/* Next button */
ABS_RIGHTNORMAL, ABS_RIGHTPRESSED, ABS_RIGHTDISABLED
};
- int stateNum = btnNext ? 3 : 0;
+ int stateNum = button == DIRECTION_FORWARD ? 3 : 0;
if (pressed)
stateNum += 1;
else
}
else
{
- int style = btnNext ? DFCS_SCROLLRIGHT : DFCS_SCROLLLEFT;
+ int style = button == DIRECTION_FORWARD ? DFCS_SCROLLRIGHT : DFCS_SCROLLLEFT;
if (pressed)
style |= DFCS_PUSHED;
else
DrawFrameControl(hdc, r, DFC_SCROLL, style);
}
}
-
-
-static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+/* paint a title with buttons and month/year string */
+static void MONTHCAL_PaintTitle(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
{
static const WCHAR fmt_monthW[] = { '%','s',' ','%','l','d',0 };
- RECT *title=&infoPtr->title;
- RECT *titlemonth=&infoPtr->titlemonth;
- RECT *titleyear=&infoPtr->titleyear;
- RECT dayrect;
- int i, j, m, mask, day, prevMonth;
- int textHeight = infoPtr->textHeight;
- SIZE size;
- HBRUSH hbr;
- HFONT currentFont;
- WCHAR buf[20];
- WCHAR buf1[20];
- WCHAR buf2[32];
- COLORREF oldTextColor, oldBkColor;
- RECT rcTemp;
- RECT rcDay; /* used in MONTHCAL_CalcDayRect() */
- int startofprescal;
- SYSTEMTIME st;
+ RECT *title = &infoPtr->calendars[calIdx].title;
+ const SYSTEMTIME *st = &infoPtr->calendars[calIdx].month;
+ WCHAR buf_month[80], buf_fmt[80];
+ SIZE sz;
- oldTextColor = SetTextColor(hdc, comctl32_color.clrWindowText);
+ /* fill header box */
+ FillRect(hdc, title, infoPtr->brushes[BrushTitle]);
- /* fill background */
- hbr = CreateSolidBrush (infoPtr->bk);
- FillRect(hdc, &ps->rcPaint, hbr);
- DeleteObject(hbr);
+ /* month/year string */
+ SetBkColor(hdc, infoPtr->colors[MCSC_TITLEBK]);
+ SetTextColor(hdc, infoPtr->colors[MCSC_TITLETEXT]);
+ SelectObject(hdc, infoPtr->hBoldFont);
- /* draw header */
- if(IntersectRect(&rcTemp, &(ps->rcPaint), title))
- {
- hbr = CreateSolidBrush(infoPtr->titlebk);
- FillRect(hdc, title, hbr);
- DeleteObject(hbr);
- }
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1 + st->wMonth - 1,
+ buf_month, countof(buf_month));
+
+ wsprintfW(buf_fmt, fmt_monthW, buf_month, st->wYear);
+ DrawTextW(hdc, buf_fmt, strlenW(buf_fmt), title,
+ DT_CENTER | DT_VCENTER | DT_SINGLELINE);
- /* if the previous button is pressed draw it depressed */
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &infoPtr->titlebtnprev))
- paint_button(infoPtr, hdc, FALSE);
+ /* update title rectangles with current month - used while testing hits */
+ GetTextExtentPoint32W(hdc, buf_fmt, strlenW(buf_fmt), &sz);
+ infoPtr->calendars[calIdx].titlemonth.left = title->right / 2 + title->left / 2 - sz.cx / 2;
+ infoPtr->calendars[calIdx].titleyear.right = title->right / 2 + title->left / 2 + sz.cx / 2;
- /* if next button is depressed draw it depressed */
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &infoPtr->titlebtnnext))
- paint_button(infoPtr, hdc, TRUE);
+ GetTextExtentPoint32W(hdc, buf_month, strlenW(buf_month), &sz);
+ infoPtr->calendars[calIdx].titlemonth.right = infoPtr->calendars[calIdx].titlemonth.left + sz.cx;
+ infoPtr->calendars[calIdx].titleyear.left = infoPtr->calendars[calIdx].titlemonth.right;
+}
- oldBkColor = SetBkColor(hdc, infoPtr->titlebk);
- SetTextColor(hdc, infoPtr->titletxt);
- currentFont = SelectObject(hdc, infoPtr->hBoldFont);
+static void MONTHCAL_PaintWeeknumbers(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
+{
+ const SYSTEMTIME *date = &infoPtr->calendars[calIdx].month;
+ static const WCHAR fmt_weekW[] = { '%','d',0 };
+ INT mindays, weeknum, weeknum1, startofprescal;
+ INT i, prev_month;
+ SYSTEMTIME st;
+ WCHAR buf[80];
+ HPEN old_pen;
+ RECT r;
- GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+infoPtr->curSel.wMonth -1,
- buf1,countof(buf1));
- wsprintfW(buf, fmt_monthW, buf1, infoPtr->curSel.wYear);
+ if (!(infoPtr->dwStyle & MCS_WEEKNUMBERS)) return;
- if(IntersectRect(&rcTemp, &(ps->rcPaint), title))
+ MONTHCAL_GetMinDate(infoPtr, &st);
+ startofprescal = st.wDay;
+ st = *date;
+
+ prev_month = date->wMonth - 1;
+ if(prev_month == 0) prev_month = 12;
+
+ /*
+ Rules what week to call the first week of a new year:
+ LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?):
+ The week containing Jan 1 is the first week of year
+ LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany):
+ First week of year must contain 4 days of the new year
+ LOCALE_IFIRSTWEEKOFYEAR == 1 (what contries?)
+ The first week of the year must contain only days of the new year
+ */
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, countof(buf));
+ weeknum = atoiW(buf);
+ switch (weeknum)
{
- DrawTextW(hdc, buf, strlenW(buf), title,
- DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+ case 1: mindays = 6;
+ break;
+ case 2: mindays = 3;
+ break;
+ case 0: mindays = 0;
+ break;
+ default:
+ WARN("Unknown LOCALE_IFIRSTWEEKOFYEAR value %d, defaulting to 0\n", weeknum);
+ mindays = 0;
}
-/* titlemonth left/right contained rect for whole titletxt('June 1999')
- * MCM_HitTestInfo wants month & year rects, so prepare these now.
- *(no, we can't draw them separately; the whole text is centered)
- */
- GetTextExtentPoint32W(hdc, buf, strlenW(buf), &size);
- titlemonth->left = title->right / 2 + title->left / 2 - size.cx / 2;
- titleyear->right = title->right / 2 + title->left / 2 + size.cx / 2;
- GetTextExtentPoint32W(hdc, buf1, strlenW(buf1), &size);
- titlemonth->right = titlemonth->left + size.cx;
- titleyear->left = titlemonth->right;
-
- /* draw month area */
- rcTemp.top=infoPtr->wdays.top;
- rcTemp.left=infoPtr->wdays.left;
- rcTemp.bottom=infoPtr->todayrect.bottom;
- rcTemp.right =infoPtr->todayrect.right;
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcTemp))
+ if (date->wMonth == 1)
+ {
+ /* calculate all those exceptions for january */
+ st.wDay = st.wMonth = 1;
+ weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
+ if ((infoPtr->firstDay - weeknum1) % 7 > mindays)
+ weeknum = 1;
+ else
+ {
+ weeknum = 0;
+ for(i = 0; i < 11; i++)
+ weeknum += MONTHCAL_MonthLength(i+1, date->wYear - 1);
+
+ weeknum += startofprescal + 7;
+ weeknum /= 7;
+ st.wYear -= 1;
+ weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
+ if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
+ }
+ }
+ else
{
- hbr = CreateSolidBrush(infoPtr->monthbk);
- FillRect(hdc, &rcTemp, hbr);
- DeleteObject(hbr);
+ weeknum = 0;
+ for(i = 0; i < prev_month - 1; i++)
+ weeknum += MONTHCAL_MonthLength(i+1, date->wYear);
+
+ weeknum += startofprescal + 7;
+ weeknum /= 7;
+ st.wDay = st.wMonth = 1;
+ weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
+ if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
}
-/* draw line under day abbreviations */
+ r = infoPtr->calendars[calIdx].weeknums;
- MoveToEx(hdc, infoPtr->days.left + 3, title->bottom + textHeight + 1, NULL);
- LineTo(hdc, infoPtr->days.right - 3, title->bottom + textHeight + 1);
+ /* erase whole week numbers area */
+ FillRect(hdc, &r, infoPtr->brushes[BrushTitle]);
+ SetTextColor(hdc, infoPtr->colors[MCSC_TITLEBK]);
- prevMonth = infoPtr->curSel.wMonth - 1;
- if(prevMonth == 0) /* if curSel.wMonth is january(1) prevMonth is */
- prevMonth = 12; /* december(12) of the previous year */
+ /* reduce rectangle to one week number */
+ r.bottom = r.top + infoPtr->height_increment;
- infoPtr->wdays.left = infoPtr->days.left = infoPtr->weeknums.right;
+ for(i = 0; i < 6; i++) {
+ if((i == 0) && (weeknum > 50))
+ {
+ wsprintfW(buf, fmt_weekW, weeknum);
+ weeknum = 0;
+ }
+ else if((i == 5) && (weeknum > 47))
+ {
+ wsprintfW(buf, fmt_weekW, 1);
+ }
+ else
+ wsprintfW(buf, fmt_weekW, weeknum + i);
- /* draw day abbreviations */
- SelectObject(hdc, infoPtr->hFont);
- SetBkColor(hdc, infoPtr->monthbk);
- SetTextColor(hdc, infoPtr->trailingtxt);
+ DrawTextW(hdc, buf, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+ OffsetRect(&r, 0, infoPtr->height_increment);
+ }
- /* rectangle to draw a single day abbreviation within */
- dayrect = infoPtr->wdays;
- dayrect.right = dayrect.left + infoPtr->width_increment;
+ /* line separator for week numbers column */
+ old_pen = SelectObject(hdc, infoPtr->pens[PenText]);
+ MoveToEx(hdc, infoPtr->calendars[calIdx].weeknums.right, infoPtr->calendars[calIdx].weeknums.top + 3 , NULL);
+ LineTo(hdc, infoPtr->calendars[calIdx].weeknums.right, infoPtr->calendars[calIdx].weeknums.bottom);
+ SelectObject(hdc, old_pen);
+}
- i = infoPtr->firstDay;
+/* bottom today date */
+static void MONTHCAL_PaintTodayTitle(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+ static const WCHAR fmt_todayW[] = { '%','s',' ','%','s',0 };
+ WCHAR buf_todayW[30], buf_dateW[20], buf[80];
+ RECT text_rect, box_rect;
+ HFONT old_font;
+ INT col;
- for(j = 0; j < 7; j++) {
- GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf));
- DrawTextW(hdc, buf, strlenW(buf), &dayrect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
- dayrect.left += infoPtr->width_increment;
- dayrect.right += infoPtr->width_increment;
+ if(infoPtr->dwStyle & MCS_NOTODAY) return;
+
+ if (!LoadStringW(COMCTL32_hModule, IDM_TODAY, buf_todayW, countof(buf_todayW)))
+ {
+ static const WCHAR todayW[] = { 'T','o','d','a','y',':',0 };
+ WARN("Can't load resource\n");
+ strcpyW(buf_todayW, todayW);
}
- /* draw day numbers; first, the previous month */
- MONTHCAL_GetMinDate(infoPtr, &st);
- day = st.wDay;
- startofprescal = day;
- mask = 1<<(day-1);
-
- i = 0;
- m = 0;
- while(day <= MONTHCAL_MonthLength(prevMonth, infoPtr->curSel.wYear)) {
- MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
- {
- MONTHCAL_DrawDay(infoPtr, hdc, day, prevMonth, i, 0,
- infoPtr->monthdayState[m] & mask);
- }
+ col = infoPtr->dwStyle & MCS_NOTODAYCIRCLE ? 0 : 1;
+ if (infoPtr->dwStyle & MCS_WEEKNUMBERS) col--;
+ MONTHCAL_CalcDayRect(infoPtr, &text_rect, col, 6);
+ box_rect = text_rect;
+
+ GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &infoPtr->todaysDate, NULL,
+ buf_dateW, countof(buf_dateW));
+ old_font = SelectObject(hdc, infoPtr->hBoldFont);
+ SetTextColor(hdc, infoPtr->colors[MCSC_TEXT]);
- mask<<=1;
- day++;
- i++;
+ wsprintfW(buf, fmt_todayW, buf_todayW, buf_dateW);
+ DrawTextW(hdc, buf, -1, &text_rect, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+ DrawTextW(hdc, buf, -1, &text_rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
+ if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE)) {
+ OffsetRect(&box_rect, -infoPtr->width_increment, 0);
+ MONTHCAL_Circle(infoPtr, hdc, &box_rect);
}
-/* draw `current' month */
+ SelectObject(hdc, old_font);
+}
- day = 1; /* start at the beginning of the current month */
+/* today mark + focus */
+static void MONTHCAL_PaintFocusAndCircle(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+ if((infoPtr->minSel.wMonth == infoPtr->todaysDate.wMonth) &&
+ (infoPtr->minSel.wYear == infoPtr->todaysDate.wYear) &&
+ !(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
+ {
+ MONTHCAL_CircleDay(infoPtr, hdc, &infoPtr->todaysDate);
+ }
- infoPtr->firstDayplace = i;
- SetTextColor(hdc, infoPtr->txt);
- m++;
- mask = 1;
+ if(!MONTHCAL_IsDateEqual(&infoPtr->focusedSel, &st_null))
+ {
+ RECT r;
+ MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->focusedSel, &r);
+ DrawFocusRect(hdc, &r);
+ }
+}
- /* draw the first week of the current month */
- while(i<7) {
- MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
- {
- MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->curSel.wMonth, i, 0,
- infoPtr->monthdayState[m] & mask);
- }
+/* months before first calendar month and after last calendar month */
+static void MONTHCAL_PaintLeadTrailMonths(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+ INT mask, length;
+ SYSTEMTIME st_max, st;
+
+ if (infoPtr->dwStyle & MCS_NOTRAILINGDATES) return;
- mask<<=1;
- day++;
- i++;
+ SetTextColor(hdc, infoPtr->colors[MCSC_TRAILINGTEXT]);
+
+ /* draw prev month */
+ MONTHCAL_GetMinDate(infoPtr, &st);
+ mask = 1 << (st.wDay-1);
+ /* December and January both 31 days long, so no worries if wrapped */
+ length = MONTHCAL_MonthLength(infoPtr->calendars[0].month.wMonth - 1,
+ infoPtr->calendars[0].month.wYear);
+ while(st.wDay <= length)
+ {
+ MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[0] & mask, ps);
+ mask <<= 1;
+ st.wDay++;
}
- j = 1; /* move to the 2nd week of the current month */
- i = 0; /* move back to sunday */
- while(day <= MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear)) {
- MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
- {
- MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->curSel.wMonth, i, j,
- infoPtr->monthdayState[m] & mask);
- }
- mask<<=1;
- day++;
- i++;
- if(i>6) { /* past saturday, goto the next weeks sunday */
- i = 0;
- j++;
- }
+ /* draw next month */
+ st = infoPtr->calendars[infoPtr->cal_num-1].month;
+ st.wDay = 1;
+ MONTHCAL_GetNextMonth(&st);
+ MONTHCAL_GetMaxDate(infoPtr, &st_max);
+ mask = 1;
+
+ while(st.wDay <= st_max.wDay)
+ {
+ MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[2] & mask, ps);
+ mask <<= 1;
+ st.wDay++;
}
+}
+
+/* paint a calendar area */
+static void MONTHCAL_PaintCalendar(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
+{
+ const SYSTEMTIME *date = &infoPtr->calendars[calIdx].month;
+ INT prev_month, i, j, length;
+ RECT r, fill_bk_rect;
+ SYSTEMTIME st;
+ WCHAR buf[80];
+ HPEN old_pen;
+ int mask;
-/* draw `next' month */
+ /* fill whole days area - from week days area to today note rectangle */
+ fill_bk_rect = infoPtr->calendars[calIdx].wdays;
+ fill_bk_rect.bottom = infoPtr->calendars[calIdx].days.bottom +
+ (infoPtr->todayrect.bottom - infoPtr->todayrect.top);
- day = 1; /* start at the first day of the next month */
- m++;
- mask = 1;
+ FillRect(hdc, &fill_bk_rect, infoPtr->brushes[BrushMonth]);
- SetTextColor(hdc, infoPtr->trailingtxt);
- while((i<7) &&(j<6)) {
- MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
- {
- MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->curSel.wMonth + 1, i, j,
- infoPtr->monthdayState[m] & mask);
- }
+ /* draw line under day abbreviations */
+ old_pen = SelectObject(hdc, infoPtr->pens[PenText]);
+ MoveToEx(hdc, infoPtr->calendars[calIdx].days.left + 3,
+ infoPtr->calendars[calIdx].title.bottom + infoPtr->textHeight + 1, NULL);
+ LineTo(hdc, infoPtr->calendars[calIdx].days.right - 3,
+ infoPtr->calendars[calIdx].title.bottom + infoPtr->textHeight + 1);
+ SelectObject(hdc, old_pen);
- mask<<=1;
- day++;
- i++;
- if(i==7) { /* past saturday, go to next week's sunday */
- i = 0;
- j++;
- }
+ prev_month = date->wMonth - 1;
+ if (prev_month == 0) prev_month = 12;
+
+ infoPtr->calendars[calIdx].wdays.left = infoPtr->calendars[calIdx].days.left =
+ infoPtr->calendars[calIdx].weeknums.right;
+
+ /* draw day abbreviations */
+ SelectObject(hdc, infoPtr->hFont);
+ SetBkColor(hdc, infoPtr->colors[MCSC_MONTHBK]);
+ SetTextColor(hdc, infoPtr->colors[MCSC_TITLEBK]);
+ /* rectangle to draw a single day abbreviation within */
+ r = infoPtr->calendars[calIdx].wdays;
+ r.right = r.left + infoPtr->width_increment;
+
+ i = infoPtr->firstDay;
+ for(j = 0; j < 7; j++) {
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf));
+ DrawTextW(hdc, buf, strlenW(buf), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+ OffsetRect(&r, infoPtr->width_increment, 0);
}
- SetTextColor(hdc, infoPtr->txt);
- /* draw today mark rectangle */
- if((infoPtr->curSel.wMonth == infoPtr->todaysDate.wMonth) &&
- (infoPtr->curSel.wYear == infoPtr->todaysDate.wYear) &&
- !(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
+ /* draw current month */
+ SetTextColor(hdc, infoPtr->colors[MCSC_TEXT]);
+ st = *date;
+ st.wDay = 1;
+ mask = 1;
+ length = MONTHCAL_MonthLength(date->wMonth, date->wYear);
+ while(st.wDay <= length)
{
- MONTHCAL_CircleDay(infoPtr, hdc, infoPtr->todaysDate.wDay, infoPtr->todaysDate.wMonth);
+ MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[1] & mask, ps);
+ mask <<= 1;
+ st.wDay++;
}
+}
- /* draw focused day */
- if(!MONTHCAL_IsDateEqual(&infoPtr->focusedSel, &st_null))
+static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+ COLORREF old_text_clr, old_bk_clr;
+ HFONT old_font;
+ INT i;
+
+ old_text_clr = SetTextColor(hdc, comctl32_color.clrWindowText);
+ old_bk_clr = GetBkColor(hdc);
+ old_font = GetCurrentObject(hdc, OBJ_FONT);
+
+ for (i = 0; i < infoPtr->cal_num; i++)
{
- MONTHCAL_CalcPosFromDay(infoPtr, infoPtr->focusedSel.wDay,
- infoPtr->focusedSel.wMonth, &rcDay);
+ RECT *title = &infoPtr->calendars[i].title;
+ RECT r;
- DrawFocusRect(hdc, &rcDay);
- }
+ /* draw title, redraw all its elements */
+ if (IntersectRect(&r, &(ps->rcPaint), title))
+ MONTHCAL_PaintTitle(infoPtr, hdc, ps, i);
- /* draw `today' date if style allows it, and draw a circle before today's
- * date if necessary */
- if(!(infoPtr->dwStyle & MCS_NOTODAY)) {
- static const WCHAR todayW[] = { 'T','o','d','a','y',':',0 };
- static const WCHAR fmt_todayW[] = { '%','s',' ','%','s',0 };
- RECT rtoday;
-
- if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE)) {
- /*day is the number of days from nextmonth we put on the calendar */
- MONTHCAL_CircleDay(infoPtr, hdc,
- day+MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear),
- infoPtr->curSel.wMonth);
- }
- if (!LoadStringW(COMCTL32_hModule, IDM_TODAY, buf1, countof(buf1)))
- {
- WARN("Can't load resource\n");
- strcpyW(buf1, todayW);
- }
- MONTHCAL_CalcDayRect(infoPtr, &rtoday, 1, 6);
- GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &infoPtr->todaysDate, NULL,
- buf2, countof(buf2));
- wsprintfW(buf, fmt_todayW, buf1, buf2);
- SelectObject(hdc, infoPtr->hBoldFont);
-
- DrawTextW(hdc, buf, -1, &rtoday, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE);
- if(IntersectRect(&rcTemp, &(ps->rcPaint), &rtoday))
- {
- DrawTextW(hdc, buf, -1, &rtoday, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
- }
- SelectObject(hdc, infoPtr->hFont);
- }
-
- /* eventually draw week numbers */
- if(infoPtr->dwStyle & MCS_WEEKNUMBERS) {
- static const WCHAR fmt_weekW[] = { '%','d',0 }; /* week numbers format */
- int mindays, weeknum, weeknum1;
-
- /* Rules what week to call the first week of a new year:
- LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?):
- The week containing Jan 1 is the first week of year
- LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany):
- First week of year must contain 4 days of the new year
- LOCALE_IFIRSTWEEKOFYEAR == 1 (what contries?)
- The first week of the year must contain only days of the new year
- */
- GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, countof(buf));
- weeknum = atoiW(buf);
- switch (weeknum)
- {
- case 1: mindays = 6;
- break;
- case 2: mindays = 3;
- break;
- case 0:
- default:
- mindays = 0;
- }
- if (infoPtr->curSel.wMonth < 2)
- {
- /* calculate all those exceptions for january */
- weeknum1 = MONTHCAL_CalculateDayOfWeek(1, 1, infoPtr->curSel.wYear);
- if ((infoPtr->firstDay - weeknum1) % 7 > mindays)
- weeknum = 1;
- else
- {
- weeknum = 0;
- for(i = 0; i < 11; i++)
- weeknum += MONTHCAL_MonthLength(i+1, infoPtr->curSel.wYear - 1);
-
- weeknum += startofprescal + 7;
- weeknum /= 7;
- weeknum1 = MONTHCAL_CalculateDayOfWeek(1, 1, infoPtr->curSel.wYear - 1);
- if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
- }
- }
- else
- {
- weeknum = 0;
- for(i = 0; i < prevMonth - 1; i++)
- weeknum += MONTHCAL_MonthLength(i+1, infoPtr->curSel.wYear);
+ /* draw calendar area */
+ UnionRect(&r, &infoPtr->calendars[i].wdays, &infoPtr->todayrect);
+ if (IntersectRect(&r, &(ps->rcPaint), &r))
+ MONTHCAL_PaintCalendar(infoPtr, hdc, ps, i);
- weeknum += startofprescal + 7;
- weeknum /= 7;
- weeknum1 = MONTHCAL_CalculateDayOfWeek(1, 1, infoPtr->curSel.wYear);
- if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
- }
+ /* week numbers */
+ MONTHCAL_PaintWeeknumbers(infoPtr, hdc, ps, i);
+ }
- dayrect = infoPtr->weeknums;
- dayrect.bottom = dayrect.top + infoPtr->height_increment;
+ /* partially visible months */
+ MONTHCAL_PaintLeadTrailMonths(infoPtr, hdc, ps);
- for(i = 0; i < 6; i++) {
- if((i == 0) && (weeknum > 50))
- {
- wsprintfW(buf, fmt_weekW, weeknum);
- weeknum = 0;
- }
- else if((i == 5) && (weeknum > 47))
- {
- wsprintfW(buf, fmt_weekW, 1);
- }
- else
- wsprintfW(buf, fmt_weekW, weeknum + i);
+ /* focus and today rectangle */
+ MONTHCAL_PaintFocusAndCircle(infoPtr, hdc, ps);
- DrawTextW(hdc, buf, -1, &dayrect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
- dayrect.top += infoPtr->height_increment;
- dayrect.bottom += infoPtr->height_increment;
- }
+ /* today at the bottom left */
+ MONTHCAL_PaintTodayTitle(infoPtr, hdc, ps);
- MoveToEx(hdc, infoPtr->weeknums.right, infoPtr->weeknums.top + 3 , NULL);
- LineTo(hdc, infoPtr->weeknums.right, infoPtr->weeknums.bottom);
- }
+ /* navigation buttons */
+ MONTHCAL_PaintButton(infoPtr, hdc, DIRECTION_BACKWARD);
+ MONTHCAL_PaintButton(infoPtr, hdc, DIRECTION_FORWARD);
- /* currentFont was font at entering Refresh */
- SetBkColor(hdc, oldBkColor);
- SelectObject(hdc, currentFont);
- SetTextColor(hdc, oldTextColor);
+ /* restore context */
+ SetBkColor(hdc, old_bk_clr);
+ SelectObject(hdc, old_font);
+ SetTextColor(hdc, old_text_clr);
}
-
static LRESULT
-MONTHCAL_GetMinReqRect(const MONTHCAL_INFO *infoPtr, LPRECT lpRect)
+MONTHCAL_GetMinReqRect(const MONTHCAL_INFO *infoPtr, RECT *rect)
{
- TRACE("rect %p\n", lpRect);
+ TRACE("rect %p\n", rect);
- if(!lpRect) return FALSE;
+ if(!rect) return FALSE;
- lpRect->left = infoPtr->title.left;
- lpRect->top = infoPtr->title.top;
- lpRect->right = infoPtr->title.right;
- lpRect->bottom = infoPtr->todayrect.bottom;
+ *rect = infoPtr->calendars[0].title;
+ rect->bottom = infoPtr->calendars[0].days.bottom + infoPtr->todayrect.bottom -
+ infoPtr->todayrect.top;
- AdjustWindowRect(lpRect, infoPtr->dwStyle, FALSE);
+ AdjustWindowRect(rect, infoPtr->dwStyle, FALSE);
/* minimal rectangle is zero based */
- OffsetRect(lpRect, -lpRect->left, -lpRect->top);
+ OffsetRect(rect, -rect->left, -rect->top);
- TRACE("%s\n", wine_dbgstr_rect(lpRect));
+ TRACE("%s\n", wine_dbgstr_rect(rect));
return TRUE;
}
+static COLORREF
+MONTHCAL_GetColor(const MONTHCAL_INFO *infoPtr, UINT index)
+{
+ TRACE("%p, %d\n", infoPtr, index);
+
+ if (index > MCSC_TRAILINGTEXT) return -1;
+ return infoPtr->colors[index];
+}
static LRESULT
-MONTHCAL_GetColor(const MONTHCAL_INFO *infoPtr, INT index)
+MONTHCAL_SetColor(MONTHCAL_INFO *infoPtr, UINT index, COLORREF color)
{
- TRACE("\n");
+ enum CachedBrush type;
+ COLORREF prev;
- switch(index) {
- case MCSC_BACKGROUND:
- return infoPtr->bk;
- case MCSC_TEXT:
- return infoPtr->txt;
- case MCSC_TITLEBK:
- return infoPtr->titlebk;
- case MCSC_TITLETEXT:
- return infoPtr->titletxt;
- case MCSC_MONTHBK:
- return infoPtr->monthbk;
- case MCSC_TRAILINGTEXT:
- return infoPtr->trailingtxt;
- }
+ TRACE("%p, %d: color %08x\n", infoPtr, index, color);
- return -1;
-}
+ if (index > MCSC_TRAILINGTEXT) return -1;
+ prev = infoPtr->colors[index];
+ infoPtr->colors[index] = color;
-static LRESULT
-MONTHCAL_SetColor(MONTHCAL_INFO *infoPtr, INT index, COLORREF color)
-{
- COLORREF prev = -1;
-
- TRACE("%d: color %08x\n", index, color);
-
- switch(index) {
- case MCSC_BACKGROUND:
- prev = infoPtr->bk;
- infoPtr->bk = color;
- break;
- case MCSC_TEXT:
- prev = infoPtr->txt;
- infoPtr->txt = color;
- break;
- case MCSC_TITLEBK:
- prev = infoPtr->titlebk;
- infoPtr->titlebk = color;
- break;
- case MCSC_TITLETEXT:
- prev=infoPtr->titletxt;
- infoPtr->titletxt = color;
- break;
- case MCSC_MONTHBK:
- prev = infoPtr->monthbk;
- infoPtr->monthbk = color;
- break;
- case MCSC_TRAILINGTEXT:
- prev = infoPtr->trailingtxt;
- infoPtr->trailingtxt = color;
- break;
+ /* update cached brush */
+ switch (index)
+ {
+ case MCSC_BACKGROUND:
+ type = BrushBackground;
+ break;
+ case MCSC_TITLEBK:
+ type = BrushTitle;
+ break;
+ case MCSC_MONTHBK:
+ type = BrushMonth;
+ break;
+ default:
+ type = BrushLast;
+ }
+
+ if (type != BrushLast)
+ {
+ DeleteObject(infoPtr->brushes[type]);
+ infoPtr->brushes[type] = CreateSolidBrush(color);
+ }
+
+ /* update cached pen */
+ if (index == MCSC_TEXT)
+ {
+ DeleteObject(infoPtr->pens[PenText]);
+ infoPtr->pens[PenText] = CreatePen(PS_SOLID, 1, infoPtr->colors[index]);
}
InvalidateRect(infoPtr->hwndSelf, NULL, index == MCSC_BACKGROUND ? TRUE : FALSE);
return prev;
}
-
static LRESULT
MONTHCAL_GetMonthDelta(const MONTHCAL_INFO *infoPtr)
{
{
/* Native behaviour for that case is broken: invalid date number >31
got displayed at (0,0) position, current month starts always from
- (1,0) position. Should be implemnted here as well. */
+ (1,0) position. Should be implemented here as well only if there's
+ nothing else to do. */
if (day < -1)
FIXME("No bug compatibility for day=%d\n", day);
static LRESULT
MONTHCAL_GetMonthRange(const MONTHCAL_INFO *infoPtr, DWORD flag, SYSTEMTIME *st)
{
- TRACE("\n");
+ TRACE("flag=%d, st=%p\n", flag, st);
if(st)
{
switch (flag) {
case GMR_VISIBLE:
{
- /*FIXME: currently multicalendar feature isn't implemented, so entirely
- visible month is current */
- st[0] = st[1] = infoPtr->curSel;
+ st[0] = infoPtr->calendars[0].month;
+ st[1] = infoPtr->calendars[infoPtr->cal_num-1].month;
- if (infoPtr->curSel.wMonth == min_allowed_date.wMonth &&
- infoPtr->curSel.wYear == min_allowed_date.wYear)
+ if (st[0].wMonth == min_allowed_date.wMonth &&
+ st[0].wYear == min_allowed_date.wYear)
{
st[0].wDay = min_allowed_date.wDay;
}
else
st[0].wDay = 1;
- st[0].wDayOfWeek = MONTHCAL_CalculateDayOfWeek(1, st[0].wMonth, st[0].wYear);
+ MONTHCAL_CalculateDayOfWeek(&st[0], TRUE);
st[1].wDay = MONTHCAL_MonthLength(st[1].wMonth, st[1].wYear);
- st[1].wDayOfWeek = MONTHCAL_CalculateDayOfWeek(st[1].wDay, st[1].wMonth,
- st[1].wYear);
- /* a single current month used */
- return 1;
+ MONTHCAL_CalculateDayOfWeek(&st[1], TRUE);
+
+ return infoPtr->cal_num;
}
case GMR_DAYSTATE:
{
- /*FIXME: currently multicalendar feature isn't implemented,
- min date from previous month and max date from next one returned */
MONTHCAL_GetMinDate(infoPtr, &st[0]);
MONTHCAL_GetMaxDate(infoPtr, &st[1]);
break;
static LRESULT
MONTHCAL_SetDayState(const MONTHCAL_INFO *infoPtr, INT months, MONTHDAYSTATE *states)
{
- int i;
-
- TRACE("%d %p\n", months, states);
+ TRACE("%p %d %p\n", infoPtr, months, states);
if(months != infoPtr->monthRange) return 0;
- for(i = 0; i < months; i++)
- infoPtr->monthdayState[i] = states[i];
+ memcpy(infoPtr->monthdayState, states, months*sizeof(MONTHDAYSTATE));
return 1;
}
if(!curSel) return FALSE;
if(infoPtr->dwStyle & MCS_MULTISELECT) return FALSE;
- *curSel = infoPtr->curSel;
+ *curSel = infoPtr->minSel;
TRACE("%d/%d/%d\n", curSel->wYear, curSel->wMonth, curSel->wDay);
return TRUE;
}
-/* FIXME: if the specified date is not visible, make it visible */
static LRESULT
MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
{
+ SYSTEMTIME prev = infoPtr->minSel;
+ WORD day;
+
TRACE("%p\n", curSel);
if(!curSel) return FALSE;
if(infoPtr->dwStyle & MCS_MULTISELECT) return FALSE;
if(!MONTHCAL_ValidateDate(curSel)) return FALSE;
/* exit earlier if selection equals current */
- if (MONTHCAL_IsDateEqual(&infoPtr->curSel, curSel)) return TRUE;
+ if (MONTHCAL_IsDateEqual(&infoPtr->minSel, curSel)) return TRUE;
if(!MONTHCAL_IsDateInValidRange(infoPtr, curSel, FALSE)) return FALSE;
+ infoPtr->calendars[0].month = *curSel;
infoPtr->minSel = *curSel;
infoPtr->maxSel = *curSel;
- infoPtr->curSel = *curSel;
+ /* if selection is still in current month, reduce rectangle */
+ day = prev.wDay;
+ prev.wDay = curSel->wDay;
+ if (MONTHCAL_IsDateEqual(&prev, curSel))
+ {
+ RECT r_prev, r_new;
- /* FIXME: it's possible to reduce rectangle here */
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+ prev.wDay = day;
+ MONTHCAL_CalcPosFromDay(infoPtr, &prev, &r_prev);
+ MONTHCAL_CalcPosFromDay(infoPtr, curSel, &r_new);
+
+ InvalidateRect(infoPtr->hwndSelf, &r_prev, FALSE);
+ InvalidateRect(infoPtr->hwndSelf, &r_new, FALSE);
+ }
+ else
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
return TRUE;
}
infoPtr->minSel = range[1];
infoPtr->maxSel = range[0];
}
+ infoPtr->calendars[0].month = infoPtr->minSel;
/* update day of week */
- infoPtr->minSel.wDayOfWeek =
- MONTHCAL_CalculateDayOfWeek(infoPtr->minSel.wDay, infoPtr->minSel.wMonth,
- infoPtr->minSel.wYear);
- infoPtr->maxSel.wDayOfWeek =
- MONTHCAL_CalculateDayOfWeek(infoPtr->maxSel.wDay, infoPtr->maxSel.wMonth,
- infoPtr->maxSel.wYear);
+ MONTHCAL_CalculateDayOfWeek(&infoPtr->minSel, TRUE);
+ MONTHCAL_CalculateDayOfWeek(&infoPtr->maxSel, TRUE);
/* redraw if bounds changed */
/* FIXME: no actual need to redraw everything */
if(MONTHCAL_IsDateEqual(today, &infoPtr->todaysDate)) return FALSE;
- MONTHCAL_CalcPosFromDay(infoPtr, infoPtr->todaysDate.wDay,
- infoPtr->todaysDate.wMonth, &old_r);
- MONTHCAL_CalcPosFromDay(infoPtr, today->wDay, today->wMonth, &new_r);
+ MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->todaysDate, &old_r);
+ MONTHCAL_CalcPosFromDay(infoPtr, today, &new_r);
infoPtr->todaysDate = *today;
return TRUE;
}
+/* returns calendar index containing specified point, or -1 if it's background */
+static INT MONTHCAL_GetCalendarFromPoint(const MONTHCAL_INFO *infoPtr, const POINT *pt)
+{
+ RECT r;
+ INT i;
+
+ for (i = 0; i < infoPtr->cal_num; i++)
+ {
+ /* whole bounding rectangle allows some optimization to compute */
+ r.left = infoPtr->calendars[i].title.left;
+ r.top = infoPtr->calendars[i].title.top;
+ r.bottom = infoPtr->calendars[i].days.bottom;
+ r.right = infoPtr->calendars[i].days.right;
+
+ if (PtInRect(&r, *pt)) return i;
+ }
+
+ return -1;
+}
+
+static inline UINT fill_hittest_info(const MCHITTESTINFO *src, MCHITTESTINFO *dest)
+{
+ dest->uHit = src->uHit;
+ dest->st = src->st;
+
+ if (dest->cbSize == sizeof(MCHITTESTINFO))
+ memcpy(&dest->rc, &src->rc, sizeof(MCHITTESTINFO) - MCHITTESTINFO_V1_SIZE);
+
+ return src->uHit;
+}
+
static LRESULT
MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
{
- UINT x,y;
- DWORD retval;
- int day,wday,wnum;
+ INT day, wday, wnum, calIdx;
+ MCHITTESTINFO htinfo;
+ SYSTEMTIME ht_month;
+ UINT x, y;
if(!lpht || lpht->cbSize < MCHITTESTINFO_V1_SIZE) return -1;
x = lpht->pt.x;
y = lpht->pt.y;
- ZeroMemory(&lpht->st, sizeof(lpht->st));
+ htinfo.st = st_null;
+
+ /* we should preserve passed fields if hit area doesn't need them */
+ if (lpht->cbSize == sizeof(MCHITTESTINFO))
+ memcpy(&htinfo.rc, &lpht->rc, sizeof(MCHITTESTINFO) - MCHITTESTINFO_V1_SIZE);
/* Comment in for debugging...
TRACE("%d %d wd[%d %d %d %d] d[%d %d %d %d] t[%d %d %d %d] wn[%d %d %d %d]\n", x, y,
infoPtr->weeknums.top, infoPtr->weeknums.bottom);
*/
- /* are we in the header? */
+ /* guess in what calendar we are */
+ calIdx = MONTHCAL_GetCalendarFromPoint(infoPtr, &lpht->pt);
+ if (calIdx == -1)
+ {
+ if (PtInRect(&infoPtr->todayrect, lpht->pt))
+ {
+ htinfo.uHit = MCHT_TODAYLINK;
+ htinfo.rc = infoPtr->todayrect;
+ }
+ else
+ /* outside of calendar area? What's left must be background :-) */
+ htinfo.uHit = MCHT_CALENDARBK;
+
+ return fill_hittest_info(&htinfo, lpht);
+ }
+
+ ht_month = infoPtr->calendars[calIdx].month;
- if(PtInRect(&infoPtr->title, lpht->pt)) {
- if(PtInRect(&infoPtr->titlebtnprev, lpht->pt)) {
- retval = MCHT_TITLEBTNPREV;
- goto done;
+ /* are we in the header? */
+ if (PtInRect(&infoPtr->calendars[calIdx].title, lpht->pt)) {
+ /* FIXME: buttons hittesting could be optimized cause maximum
+ two calendars have buttons */
+ if (calIdx == 0 && PtInRect(&infoPtr->titlebtnprev, lpht->pt))
+ {
+ htinfo.uHit = MCHT_TITLEBTNPREV;
+ htinfo.rc = infoPtr->titlebtnprev;
}
- if(PtInRect(&infoPtr->titlebtnnext, lpht->pt)) {
- retval = MCHT_TITLEBTNNEXT;
- goto done;
+ else if (PtInRect(&infoPtr->titlebtnnext, lpht->pt))
+ {
+ htinfo.uHit = MCHT_TITLEBTNNEXT;
+ htinfo.rc = infoPtr->titlebtnnext;
}
- if(PtInRect(&infoPtr->titlemonth, lpht->pt)) {
- retval = MCHT_TITLEMONTH;
- goto done;
+ else if (PtInRect(&infoPtr->calendars[calIdx].titlemonth, lpht->pt))
+ {
+ htinfo.uHit = MCHT_TITLEMONTH;
+ htinfo.rc = infoPtr->calendars[calIdx].titlemonth;
+ htinfo.iOffset = calIdx;
+ }
+ else if (PtInRect(&infoPtr->calendars[calIdx].titleyear, lpht->pt))
+ {
+ htinfo.uHit = MCHT_TITLEYEAR;
+ htinfo.rc = infoPtr->calendars[calIdx].titleyear;
+ htinfo.iOffset = calIdx;
}
- if(PtInRect(&infoPtr->titleyear, lpht->pt)) {
- retval = MCHT_TITLEYEAR;
- goto done;
+ else
+ {
+ htinfo.uHit = MCHT_TITLE;
+ htinfo.rc = infoPtr->calendars[calIdx].title;
+ htinfo.iOffset = calIdx;
}
- retval = MCHT_TITLE;
- goto done;
- }
-
- day = MONTHCAL_CalcDayFromPos(infoPtr,x,y,&wday,&wnum);
- if(PtInRect(&infoPtr->wdays, lpht->pt)) {
- retval = MCHT_CALENDARDAY;
- lpht->st.wYear = infoPtr->curSel.wYear;
- lpht->st.wMonth = (day < 1)? infoPtr->curSel.wMonth -1 : infoPtr->curSel.wMonth;
- lpht->st.wDay = (day < 1)?
- MONTHCAL_MonthLength(infoPtr->curSel.wMonth-1, infoPtr->curSel.wYear) -day : day;
- goto done;
- }
- if(PtInRect(&infoPtr->weeknums, lpht->pt)) {
- retval = MCHT_CALENDARWEEKNUM;
- lpht->st.wYear = infoPtr->curSel.wYear;
- lpht->st.wMonth = (day < 1) ? infoPtr->curSel.wMonth -1 :
- (day > MONTHCAL_MonthLength(infoPtr->curSel.wMonth,infoPtr->curSel.wYear)) ?
- infoPtr->curSel.wMonth +1 :infoPtr->curSel.wMonth;
- lpht->st.wDay = (day < 1 ) ?
- MONTHCAL_MonthLength(infoPtr->curSel.wMonth-1,infoPtr->curSel.wYear) -day :
- (day > MONTHCAL_MonthLength(infoPtr->curSel.wMonth,infoPtr->curSel.wYear)) ?
- day - MONTHCAL_MonthLength(infoPtr->curSel.wMonth,infoPtr->curSel.wYear) : day;
- goto done;
- }
- if(PtInRect(&infoPtr->days, lpht->pt))
+ return fill_hittest_info(&htinfo, lpht);
+ }
+
+ /* days area (including week days and week numbers */
+ day = MONTHCAL_CalcDayFromPos(infoPtr, x, y, &wday, &wnum);
+ if (PtInRect(&infoPtr->calendars[calIdx].wdays, lpht->pt))
+ {
+ htinfo.uHit = MCHT_CALENDARDAY;
+ htinfo.iOffset = calIdx;
+ htinfo.st.wYear = ht_month.wYear;
+ htinfo.st.wMonth = (day < 1) ? ht_month.wMonth -1 : ht_month.wMonth;
+ htinfo.st.wDay = (day < 1) ?
+ MONTHCAL_MonthLength(ht_month.wMonth-1, ht_month.wYear) - day : day;
+
+ MONTHCAL_CalcDayXY(infoPtr, &htinfo.st, &htinfo.iCol, &htinfo.iRow);
+ }
+ else if(PtInRect(&infoPtr->calendars[calIdx].weeknums, lpht->pt))
+ {
+ htinfo.uHit = MCHT_CALENDARWEEKNUM;
+ htinfo.st.wYear = ht_month.wYear;
+ htinfo.iOffset = calIdx;
+
+ if (day < 1)
+ {
+ htinfo.st.wMonth = ht_month.wMonth - 1;
+ htinfo.st.wDay = MONTHCAL_MonthLength(ht_month.wMonth-1, ht_month.wYear) - day;
+ }
+ else if (day > MONTHCAL_MonthLength(ht_month.wMonth, ht_month.wYear))
+ {
+ htinfo.st.wMonth = ht_month.wMonth + 1;
+ htinfo.st.wDay = day - MONTHCAL_MonthLength(ht_month.wMonth, ht_month.wYear);
+ }
+ else
+ {
+ htinfo.st.wMonth = ht_month.wMonth;
+ htinfo.st.wDay = day;
+ }
+ }
+ else if(PtInRect(&infoPtr->calendars[calIdx].days, lpht->pt))
{
- lpht->st.wYear = infoPtr->curSel.wYear;
- lpht->st.wMonth = infoPtr->curSel.wMonth;
+ htinfo.iOffset = calIdx;
+ htinfo.st.wYear = ht_month.wYear;
+ htinfo.st.wMonth = ht_month.wMonth;
if (day < 1)
{
- retval = MCHT_CALENDARDATEPREV;
- MONTHCAL_GetPrevMonth(&lpht->st);
- lpht->st.wDay = MONTHCAL_MonthLength(lpht->st.wMonth, lpht->st.wYear) + day;
+ htinfo.uHit = MCHT_CALENDARDATEPREV;
+ MONTHCAL_GetPrevMonth(&htinfo.st);
+ htinfo.st.wDay = MONTHCAL_MonthLength(htinfo.st.wMonth, htinfo.st.wYear) + day;
}
- else if (day > MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear))
+ else if (day > MONTHCAL_MonthLength(ht_month.wMonth, ht_month.wYear))
{
- retval = MCHT_CALENDARDATENEXT;
- MONTHCAL_GetNextMonth(&lpht->st);
- lpht->st.wDay = day - MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+ htinfo.uHit = MCHT_CALENDARDATENEXT;
+ MONTHCAL_GetNextMonth(&htinfo.st);
+ htinfo.st.wDay = day - MONTHCAL_MonthLength(ht_month.wMonth, ht_month.wYear);
}
- else {
- retval = MCHT_CALENDARDATE;
- lpht->st.wDay = day;
+ else
+ {
+ htinfo.uHit = MCHT_CALENDARDATE;
+ htinfo.st.wDay = day;
}
+
+ MONTHCAL_CalcDayXY(infoPtr, &htinfo.st, &htinfo.iCol, &htinfo.iRow);
+ MONTHCAL_CalcDayRect(infoPtr, &htinfo.rc, htinfo.iCol, htinfo.iRow);
/* always update day of week */
- lpht->st.wDayOfWeek = MONTHCAL_CalculateDayOfWeek(lpht->st.wDay, lpht->st.wMonth,
- lpht->st.wYear);
- goto done;
- }
- if(PtInRect(&infoPtr->todayrect, lpht->pt)) {
- retval = MCHT_TODAYLINK;
- goto done;
+ MONTHCAL_CalculateDayOfWeek(&htinfo.st, TRUE);
}
-
- /* Hit nothing special? What's left must be background :-) */
-
- retval = MCHT_CALENDARBK;
- done:
- lpht->uHit = retval;
- return retval;
+ return fill_hittest_info(&htinfo, lpht);
}
/* MCN_GETDAYSTATE notification helper */
{
if(infoPtr->dwStyle & MCS_DAYSTATE) {
NMDAYSTATE nmds;
- INT i;
nmds.nmhdr.hwndFrom = infoPtr->hwndSelf;
nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
nmds.prgDayState = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE));
nmds.stStart = infoPtr->todaysDate;
- nmds.stStart.wYear = infoPtr->curSel.wYear;
- nmds.stStart.wMonth = infoPtr->curSel.wMonth;
+ nmds.stStart.wYear = infoPtr->minSel.wYear;
+ nmds.stStart.wMonth = infoPtr->minSel.wMonth;
nmds.stStart.wDay = 1;
SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmds.nmhdr.idFrom, (LPARAM)&nmds);
- for(i = 0; i < infoPtr->monthRange; i++)
- infoPtr->monthdayState[i] = nmds.prgDayState[i];
+ memcpy(infoPtr->monthdayState, nmds.prgDayState, infoPtr->monthRange*sizeof(MONTHDAYSTATE));
Free(nmds.prgDayState);
}
}
-static void MONTHCAL_GoToNextMonth(MONTHCAL_INFO *infoPtr)
+/* no valid range check performed */
+static void MONTHCAL_Scroll(MONTHCAL_INFO *infoPtr, INT delta)
{
- SYSTEMTIME next = infoPtr->curSel;
+ INT i, selIdx = -1;
- TRACE("\n");
+ for(i = 0; i < infoPtr->cal_num; i++)
+ {
+ /* save selection position to shift it later */
+ if (selIdx == -1 && MONTHCAL_CompareMonths(&infoPtr->minSel, &infoPtr->calendars[i].month) == 0)
+ selIdx = i;
- MONTHCAL_GetNextMonth(&next);
+ MONTHCAL_GetMonth(&infoPtr->calendars[i].month, delta);
+ }
- if(!MONTHCAL_IsDateInValidRange(infoPtr, &next, FALSE)) return;
+ /* selection is always shifted to first calendar */
+ if(infoPtr->dwStyle & MCS_MULTISELECT)
+ {
+ SYSTEMTIME range[2];
- infoPtr->curSel = next;
+ MONTHCAL_GetSelRange(infoPtr, range);
+ MONTHCAL_GetMonth(&range[0], delta - selIdx);
+ MONTHCAL_GetMonth(&range[1], delta - selIdx);
+ MONTHCAL_SetSelRange(infoPtr, range);
+ }
+ else
+ {
+ SYSTEMTIME st = infoPtr->minSel;
- MONTHCAL_NotifyDayState(infoPtr);
+ MONTHCAL_GetMonth(&st, delta - selIdx);
+ MONTHCAL_SetCurSel(infoPtr, &st);
+ }
}
-
-static void MONTHCAL_GoToPrevMonth(MONTHCAL_INFO *infoPtr)
+static void MONTHCAL_GoToMonth(MONTHCAL_INFO *infoPtr, enum nav_direction direction)
{
- SYSTEMTIME prev = infoPtr->curSel;
-
- TRACE("\n");
+ INT delta = infoPtr->delta ? infoPtr->delta : infoPtr->cal_num;
+ SYSTEMTIME st;
- MONTHCAL_GetPrevMonth(&prev);
+ TRACE("%s\n", direction == DIRECTION_BACKWARD ? "back" : "fwd");
- if(!MONTHCAL_IsDateInValidRange(infoPtr, &prev, FALSE)) return;
+ /* check if change allowed by range set */
+ if(direction == DIRECTION_BACKWARD)
+ {
+ st = infoPtr->calendars[0].month;
+ MONTHCAL_GetMonth(&st, -delta);
+ }
+ else
+ {
+ st = infoPtr->calendars[infoPtr->cal_num-1].month;
+ MONTHCAL_GetMonth(&st, delta);
+ }
- infoPtr->curSel = prev;
+ if(!MONTHCAL_IsDateInValidRange(infoPtr, &st, FALSE)) return;
+ MONTHCAL_Scroll(infoPtr, direction == DIRECTION_BACKWARD ? -delta : delta);
MONTHCAL_NotifyDayState(infoPtr);
+ MONTHCAL_NotifySelectionChange(infoPtr);
}
static LRESULT
if( TrackPopupMenu(hMenu, TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD,
menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL))
{
- infoPtr->curSel = infoPtr->todaysDate;
+ infoPtr->calendars[0].month = infoPtr->todaysDate;
infoPtr->minSel = infoPtr->todaysDate;
infoPtr->maxSel = infoPtr->todaysDate;
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
}
/* creates updown control and edit box */
-static void MONTHCAL_EditYear(MONTHCAL_INFO *infoPtr)
+static void MONTHCAL_EditYear(MONTHCAL_INFO *infoPtr, INT calIdx)
{
+ RECT *rc = &infoPtr->calendars[calIdx].titleyear;
+ RECT *title = &infoPtr->calendars[calIdx].title;
+
infoPtr->hWndYearEdit =
CreateWindowExW(0, WC_EDITW, 0, WS_VISIBLE | WS_CHILD | ES_READONLY,
- infoPtr->titleyear.left + 3, infoPtr->titlebtnnext.top,
- infoPtr->titleyear.right - infoPtr->titleyear.left + 4,
+ rc->left + 3, (title->bottom + title->top - infoPtr->textHeight) / 2,
+ rc->right - rc->left + 4,
infoPtr->textHeight, infoPtr->hwndSelf,
NULL, NULL, NULL);
infoPtr->hWndYearUpDown =
CreateWindowExW(0, UPDOWN_CLASSW, 0,
WS_VISIBLE | WS_CHILD | UDS_SETBUDDYINT | UDS_NOTHOUSANDS | UDS_ARROWKEYS,
- infoPtr->titleyear.right + 7, infoPtr->titlebtnnext.top,
+ rc->right + 7, (title->bottom + title->top - infoPtr->textHeight) / 2,
18, infoPtr->textHeight, infoPtr->hwndSelf,
NULL, NULL, NULL);
SendMessageW(infoPtr->hWndYearUpDown, UDM_SETRANGE, 0,
MAKELONG(max_allowed_date.wYear, min_allowed_date.wYear));
SendMessageW(infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM)infoPtr->hWndYearEdit, 0);
- SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, infoPtr->curSel.wYear);
+ SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, infoPtr->calendars[calIdx].month.wYear);
/* subclass edit box */
infoPtr->EditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hWndYearEdit,
switch(hit)
{
case MCHT_TITLEBTNNEXT:
- MONTHCAL_GoToNextMonth(infoPtr);
+ MONTHCAL_GoToMonth(infoPtr, DIRECTION_FORWARD);
infoPtr->status = MC_NEXTPRESSED;
SetTimer(infoPtr->hwndSelf, MC_PREVNEXTMONTHTIMER, MC_PREVNEXTMONTHDELAY, 0);
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
return 0;
case MCHT_TITLEBTNPREV:
- MONTHCAL_GoToPrevMonth(infoPtr);
+ MONTHCAL_GoToMonth(infoPtr, DIRECTION_BACKWARD);
infoPtr->status = MC_PREVPRESSED;
SetTimer(infoPtr->hwndSelf, MC_PREVNEXTMONTHTIMER, MC_PREVNEXTMONTHDELAY, 0);
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
i = TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD,
menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL);
- if ((i > 0) && (i < 13) && infoPtr->curSel.wMonth != i)
+ if ((i > 0) && (i < 13) && infoPtr->calendars[ht.iOffset].month.wMonth != i)
{
- infoPtr->curSel.wMonth = i;
- MONTHCAL_IsDateInValidRange(infoPtr, &infoPtr->curSel, TRUE);
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+ INT delta = i - infoPtr->calendars[ht.iOffset].month.wMonth;
+ SYSTEMTIME st;
+
+ /* check if change allowed by range set */
+ st = delta < 0 ? infoPtr->calendars[0].month :
+ infoPtr->calendars[infoPtr->cal_num-1].month;
+ MONTHCAL_GetMonth(&st, delta);
+
+ if (MONTHCAL_IsDateInValidRange(infoPtr, &st, FALSE))
+ {
+ MONTHCAL_Scroll(infoPtr, delta);
+ MONTHCAL_NotifyDayState(infoPtr);
+ MONTHCAL_NotifySelectionChange(infoPtr);
+ InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+ }
}
return 0;
}
case MCHT_TITLEYEAR:
{
- MONTHCAL_EditYear(infoPtr);
+ MONTHCAL_EditYear(infoPtr, ht.iOffset);
return 0;
}
case MCHT_TODAYLINK:
{
- infoPtr->curSel = infoPtr->todaysDate;
+ infoPtr->calendars[0].month = infoPtr->todaysDate;
infoPtr->minSel = infoPtr->todaysDate;
infoPtr->maxSel = infoPtr->todaysDate;
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
case MCHT_CALENDARDATEPREV:
case MCHT_CALENDARDATE:
{
- MONTHCAL_CopyDate(&ht.st, &infoPtr->firstSel);
-
- if(infoPtr->dwStyle & MCS_MULTISELECT)
- {
- SYSTEMTIME st[2];
+ SYSTEMTIME st[2];
- st[0] = st[1] = ht.st;
+ MONTHCAL_CopyDate(&ht.st, &infoPtr->firstSel);
- /* clear selection range */
- MONTHCAL_SetSelRange(infoPtr, st);
- }
+ st[0] = st[1] = ht.st;
+ /* clear selection range */
+ MONTHCAL_SetSelRange(infoPtr, st);
infoPtr->status = MC_SEL_LBUTDOWN;
MONTHCAL_SetDayFocus(infoPtr, &ht.st);
if((hit & MCHT_CALENDARDATE) == MCHT_CALENDARDATE)
{
- SYSTEMTIME sel = infoPtr->curSel;
+ SYSTEMTIME sel = infoPtr->minSel;
- if(!(infoPtr->dwStyle & MCS_MULTISELECT))
- {
- SYSTEMTIME st[2];
-
- st[0] = st[1] = ht.st;
- MONTHCAL_SetSelRange(infoPtr, st);
- /* will be invalidated here */
- MONTHCAL_SetCurSel(infoPtr, &st[0]);
- }
+ /* will be invalidated here */
+ MONTHCAL_SetCurSel(infoPtr, &ht.st);
/* send MCN_SELCHANGE only if new date selected */
if (!MONTHCAL_IsDateEqual(&sel, &ht.st))
switch(id) {
case MC_PREVNEXTMONTHTIMER:
- if(infoPtr->status & MC_NEXTPRESSED) MONTHCAL_GoToNextMonth(infoPtr);
- if(infoPtr->status & MC_PREVPRESSED) MONTHCAL_GoToPrevMonth(infoPtr);
+ if(infoPtr->status & MC_NEXTPRESSED) MONTHCAL_GoToMonth(infoPtr, DIRECTION_FORWARD);
+ if(infoPtr->status & MC_PREVPRESSED) MONTHCAL_GoToMonth(infoPtr, DIRECTION_BACKWARD);
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
break;
case MC_TODAYUPDATETIMER:
MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, LPARAM lParam)
{
MCHITTESTINFO ht;
- SYSTEMTIME old_focused, st_ht;
+ SYSTEMTIME st_ht;
INT hit;
RECT r;
}
st_ht = ht.st;
- old_focused = infoPtr->focusedSel;
/* if pointer is over focused day still there's nothing to do */
if(!MONTHCAL_SetDayFocus(infoPtr, &ht.st)) return 0;
- MONTHCAL_CalcPosFromDay(infoPtr, ht.st.wDay, ht.st.wMonth, &r);
+ MONTHCAL_CalcPosFromDay(infoPtr, &ht.st, &r);
if(infoPtr->dwStyle & MCS_MULTISELECT) {
SYSTEMTIME st[2];
return 0;
}
+static LRESULT
+MONTHCAL_EraseBkgnd(const MONTHCAL_INFO *infoPtr, HDC hdc)
+{
+ RECT rc;
+
+ if (!GetClipBox(hdc, &rc)) return FALSE;
+
+ FillRect(hdc, &rc, infoPtr->brushes[BrushBackground]);
+
+ return TRUE;
+}
+
+static LRESULT
+MONTHCAL_PrintClient(MONTHCAL_INFO *infoPtr, HDC hdc, DWORD options)
+{
+ FIXME("Partial Stub: (hdc=%p options=0x%08x)\n", hdc, options);
+
+ if ((options & PRF_CHECKVISIBLE) && !IsWindowVisible(infoPtr->hwndSelf))
+ return 0;
+
+ if (options & PRF_ERASEBKGND)
+ MONTHCAL_EraseBkgnd(infoPtr, hdc);
+
+ if (options & PRF_CLIENT)
+ MONTHCAL_Paint(infoPtr, hdc);
+
+ return 0;
+}
+
static LRESULT
MONTHCAL_SetFocus(const MONTHCAL_INFO *infoPtr)
{
{
static const WCHAR O0W[] = { '0','0',0 };
HDC hdc = GetDC(infoPtr->hwndSelf);
- RECT *title=&infoPtr->title;
+ RECT *title=&infoPtr->calendars[0].title;
RECT *prev=&infoPtr->titlebtnprev;
RECT *next=&infoPtr->titlebtnnext;
- RECT *titlemonth=&infoPtr->titlemonth;
- RECT *titleyear=&infoPtr->titleyear;
- RECT *wdays=&infoPtr->wdays;
- RECT *weeknumrect=&infoPtr->weeknums;
- RECT *days=&infoPtr->days;
+ RECT *titlemonth=&infoPtr->calendars[0].titlemonth;
+ RECT *titleyear=&infoPtr->calendars[0].titleyear;
+ RECT *wdays=&infoPtr->calendars[0].wdays;
+ RECT *weeknumrect=&infoPtr->calendars[0].weeknums;
+ RECT *days=&infoPtr->calendars[0].days;
RECT *todayrect=&infoPtr->todayrect;
SIZE size, sz;
TEXTMETRICW tm;
TRACE("(width=%d, height=%d)\n", Width, Height);
MONTHCAL_UpdateSize(infoPtr);
-
- /* invalidate client area and erase background */
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
return 0;
infoPtr = Alloc(sizeof(MONTHCAL_INFO));
SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
- if(infoPtr == NULL) {
- ERR( "could not allocate info memory!\n");
+ if (infoPtr == NULL) {
+ ERR("could not allocate info memory!\n");
return 0;
}
infoPtr->hwndSelf = hwnd;
infoPtr->hwndNotify = lpcs->hwndParent;
infoPtr->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
+ infoPtr->calendars = Alloc(sizeof(CALENDAR_INFO));
+ if (!infoPtr->calendars) goto fail;
+
+ infoPtr->cal_num = 1;
MONTHCAL_SetFont(infoPtr, GetStockObject(DEFAULT_GUI_FONT), FALSE);
/* initialize info structure */
- /* FIXME: calculate systemtime ->> localtime(substract timezoneinfo) */
+ /* FIXME: calculate systemtime ->> localtime(subtract timezoneinfo) */
GetLocalTime(&infoPtr->todaysDate);
MONTHCAL_SetFirstDayOfWeek(infoPtr, -1);
infoPtr->maxSelCount = (infoPtr->dwStyle & MCS_MULTISELECT) ? 7 : 1;
infoPtr->monthRange = 3;
+
infoPtr->monthdayState = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE));
- infoPtr->titlebk = comctl32_color.clrActiveCaption;
- infoPtr->titletxt = comctl32_color.clrWindow;
- infoPtr->monthbk = comctl32_color.clrWindow;
- infoPtr->trailingtxt = comctl32_color.clrGrayText;
- infoPtr->bk = comctl32_color.clrWindow;
- infoPtr->txt = comctl32_color.clrWindowText;
+ if (!infoPtr->monthdayState) goto fail;
+
+ infoPtr->colors[MCSC_BACKGROUND] = comctl32_color.clrWindow;
+ infoPtr->colors[MCSC_TEXT] = comctl32_color.clrWindowText;
+ infoPtr->colors[MCSC_TITLEBK] = comctl32_color.clrActiveCaption;
+ infoPtr->colors[MCSC_TITLETEXT] = comctl32_color.clrWindow;
+ infoPtr->colors[MCSC_MONTHBK] = comctl32_color.clrWindow;
+ infoPtr->colors[MCSC_TRAILINGTEXT] = comctl32_color.clrGrayText;
+
+ infoPtr->brushes[BrushBackground] = CreateSolidBrush(infoPtr->colors[MCSC_BACKGROUND]);
+ infoPtr->brushes[BrushTitle] = CreateSolidBrush(infoPtr->colors[MCSC_TITLEBK]);
+ infoPtr->brushes[BrushMonth] = CreateSolidBrush(infoPtr->colors[MCSC_MONTHBK]);
+
+ infoPtr->pens[PenRed] = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
+ infoPtr->pens[PenText] = CreatePen(PS_SOLID, 1, infoPtr->colors[MCSC_TEXT]);
infoPtr->minSel = infoPtr->todaysDate;
infoPtr->maxSel = infoPtr->todaysDate;
- infoPtr->curSel = infoPtr->todaysDate;
+ infoPtr->calendars[0].month = infoPtr->todaysDate;
+ infoPtr->isUnicode = TRUE;
/* call MONTHCAL_UpdateSize to set all of the dimensions */
/* of the control */
OpenThemeData (infoPtr->hwndSelf, themeClass);
return 0;
-}
+fail:
+ Free(infoPtr->monthdayState);
+ Free(infoPtr->calendars);
+ Free(infoPtr);
+ return 0;
+}
static LRESULT
MONTHCAL_Destroy(MONTHCAL_INFO *infoPtr)
{
+ INT i;
+
/* free month calendar info data */
Free(infoPtr->monthdayState);
+ Free(infoPtr->calendars);
SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0);
CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
-
+
+ for (i = 0; i < BrushLast; i++) DeleteObject(infoPtr->brushes[i]);
+ for (i = 0; i < PenLast; i++) DeleteObject(infoPtr->pens[i]);
+
Free(infoPtr);
return 0;
}
{
NMUPDOWN *nmud = (NMUPDOWN*)hdr;
- if (hdr->hwndFrom == infoPtr->hWndYearUpDown)
+ if (hdr->hwndFrom == infoPtr->hWndYearUpDown && nmud->iDelta)
{
/* year value limits are set up explicitly after updown creation */
- if ((nmud->iDelta + nmud->iPos) != infoPtr->curSel.wYear)
- {
- SYSTEMTIME new_date = infoPtr->curSel;
-
- new_date.wYear = nmud->iDelta + nmud->iPos;
- MONTHCAL_SetCurSel(infoPtr, &new_date);
- }
+ MONTHCAL_Scroll(infoPtr, 12 * nmud->iDelta);
+ MONTHCAL_NotifyDayState(infoPtr);
+ MONTHCAL_NotifySelectionChange(infoPtr);
}
}
return 0;
}
+static inline BOOL
+MONTHCAL_SetUnicodeFormat(MONTHCAL_INFO *infoPtr, BOOL isUnicode)
+{
+ BOOL prev = infoPtr->isUnicode;
+ infoPtr->isUnicode = isUnicode;
+ return prev;
+}
+
+static inline BOOL
+MONTHCAL_GetUnicodeFormat(const MONTHCAL_INFO *infoPtr)
+{
+ return infoPtr->isUnicode;
+}
+
static LRESULT WINAPI
MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
- MONTHCAL_INFO *infoPtr;
+ MONTHCAL_INFO *infoPtr = (MONTHCAL_INFO *)GetWindowLongPtrW(hwnd, 0);
TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam);
- infoPtr = MONTHCAL_GetInfoPtr(hwnd);
if (!infoPtr && (uMsg != WM_CREATE))
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
switch(uMsg)
case MCM_GETMAXTODAYWIDTH:
return MONTHCAL_GetMaxTodayWidth(infoPtr);
+ case MCM_SETUNICODEFORMAT:
+ return MONTHCAL_SetUnicodeFormat(infoPtr, (BOOL)wParam);
+
+ case MCM_GETUNICODEFORMAT:
+ return MONTHCAL_GetUnicodeFormat(infoPtr);
+
case WM_GETDLGCODE:
return DLGC_WANTARROWS | DLGC_WANTCHARS;
case WM_LBUTTONUP:
return MONTHCAL_LButtonUp(infoPtr, lParam);
- case WM_PRINTCLIENT:
case WM_PAINT:
return MONTHCAL_Paint(infoPtr, (HDC)wParam);
+ case WM_PRINTCLIENT:
+ return MONTHCAL_PrintClient(infoPtr, (HDC)wParam, (DWORD)lParam);
+
+ case WM_ERASEBKGND:
+ return MONTHCAL_EraseBkgnd(infoPtr, (HDC)wParam);
+
case WM_SETFOCUS:
return MONTHCAL_SetFocus(infoPtr);