{
HWND hwndSelf;
DWORD dwStyle; /* cached GWL_STYLE */
- COLORREF bk;
- COLORREF txt;
- COLORREF titlebk;
- COLORREF titletxt;
- COLORREF monthbk;
- COLORREF trailingtxt;
+
+ COLORREF colors[MCSC_TRAILINGTEXT+1];
+
HFONT hFont;
HFONT hBoldFont;
int textHeight;
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;
static const SYSTEMTIME max_allowed_date = { 9999, 12, 0, 31, 0, 0, 0, 0 };
static const SYSTEMTIME min_allowed_date = { 1752, 9, 0, 14, 0, 0, 0, 0 };
-
-#define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)GetWindowLongPtrW(hwnd, 0))
+/* Prev/Next buttons */
+enum nav_direction
+{
+ DIRECTION_BACKWARD,
+ DIRECTION_FORWARD
+};
/* helper functions */
return st.wDayOfWeek;
}
+/* add/substract '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++;
- }
- MONTHCAL_CalculateDayOfWeek(date, TRUE);
+ 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--;
- }
- MONTHCAL_CalculateDayOfWeek(date, TRUE);
+ return MONTHCAL_GetMonth(date, -1);
}
/* Returns full date for a first currently visible day */
{
int retval, firstDay;
RECT rcClient;
- SYSTEMTIME st = infoPtr->curSel;
+ SYSTEMTIME st = infoPtr->minSel;
GetClientRect(infoPtr->hwndSelf, &rcClient);
* [O] y : week column (zero based)
*/
static void MONTHCAL_CalcDayXY(const MONTHCAL_INFO *infoPtr,
- const SYSTEMTIME *date, int *x, int *y)
+ const SYSTEMTIME *date, INT *x, INT *y)
{
- SYSTEMTIME st = infoPtr->curSel;
+ SYSTEMTIME st = infoPtr->minSel;
LONG cmp;
int first;
st.wDay = 1;
first = (MONTHCAL_CalculateDayOfWeek(&st, FALSE) + 6 - infoPtr->firstDay) % 7;
- cmp = MONTHCAL_CompareMonths(date, &infoPtr->curSel);
+ cmp = MONTHCAL_CompareMonths(date, &infoPtr->minSel);
/* previous month */
if(cmp == -1) {
- *x = (first - MONTHCAL_MonthLength(date->wMonth, infoPtr->curSel.wYear) + date->wDay) % 7;
+ *x = (first - MONTHCAL_MonthLength(date->wMonth, infoPtr->minSel.wYear) + date->wDay) % 7;
*y = 0;
return;
}
/* next month calculation is same as for current,
just add current month length */
if(cmp == 1) {
- first += MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+ first += MONTHCAL_MonthLength(infoPtr->minSel.wMonth, infoPtr->minSel.wYear);
}
*x = (date->wDay + first) % 7;
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);
+ oldCol = SetTextColor(hdc, infoPtr->colors[MCSC_MONTHBK]);
+ oldBk = SetBkColor(hdc, infoPtr->colors[MCSC_TRAILINGTEXT]);
hbr = GetSysColorBrush(COLOR_HIGHLIGHT);
FillRect(hdc, &r, hbr);
}
-static void MONTHCAL_PaintButton(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
{
static const WCHAR fmt_monthW[] = { '%','s',' ','%','l','d',0 };
RECT *title = &infoPtr->calendars[calIdx].title;
+ const SYSTEMTIME *st = &infoPtr->calendars[calIdx].month;
WCHAR buf_month[80], buf_fmt[80];
HBRUSH hbr;
SIZE sz;
/* fill header box */
- hbr = CreateSolidBrush(infoPtr->titlebk);
+ hbr = CreateSolidBrush(infoPtr->colors[MCSC_TITLEBK]);
FillRect(hdc, title, hbr);
DeleteObject(hbr);
/* month/year string */
- SetBkColor(hdc, infoPtr->titlebk);
- SetTextColor(hdc, infoPtr->titletxt);
+ SetBkColor(hdc, infoPtr->colors[MCSC_TITLEBK]);
+ SetTextColor(hdc, infoPtr->colors[MCSC_TITLETEXT]);
SelectObject(hdc, infoPtr->hBoldFont);
- GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+infoPtr->curSel.wMonth-1,
+ GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1 + st->wMonth - 1,
buf_month, countof(buf_month));
- wsprintfW(buf_fmt, fmt_monthW, buf_month, infoPtr->curSel.wYear);
+ wsprintfW(buf_fmt, fmt_monthW, buf_month, st->wYear);
DrawTextW(hdc, buf_fmt, strlenW(buf_fmt), title,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
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;
- SYSTEMTIME st = infoPtr->curSel;
- RECT r;
- WCHAR buf[80];
INT i, prev_month;
+ SYSTEMTIME st;
+ WCHAR buf[80];
+ HBRUSH hbr;
+ RECT r;
if (!(infoPtr->dwStyle & MCS_WEEKNUMBERS)) return;
MONTHCAL_GetMinDate(infoPtr, &st);
startofprescal = st.wDay;
- st = infoPtr->curSel;
+ st = *date;
- prev_month = infoPtr->curSel.wMonth - 1;
+ prev_month = date->wMonth - 1;
if(prev_month == 0) prev_month = 12;
/*
mindays = 0;
}
- if (infoPtr->curSel.wMonth == 1)
+ if (date->wMonth == 1)
{
/* calculate all those exceptions for january */
st.wDay = st.wMonth = 1;
{
weeknum = 0;
for(i = 0; i < 11; i++)
- weeknum += MONTHCAL_MonthLength(i+1, infoPtr->curSel.wYear - 1);
+ weeknum += MONTHCAL_MonthLength(i+1, date->wYear - 1);
weeknum += startofprescal + 7;
weeknum /= 7;
{
weeknum = 0;
for(i = 0; i < prev_month - 1; i++)
- weeknum += MONTHCAL_MonthLength(i+1, infoPtr->curSel.wYear);
+ weeknum += MONTHCAL_MonthLength(i+1, date->wYear);
weeknum += startofprescal + 7;
weeknum /= 7;
}
r = infoPtr->calendars[calIdx].weeknums;
+
+ /* erase whole week numbers area */
+ hbr = CreateSolidBrush(infoPtr->colors[MCSC_MONTHBK]);
+ FillRect(hdc, &r, hbr);
+ DeleteObject(hbr);
+
+ /* reduce rectangle to one week number */
r.bottom = r.top + infoPtr->height_increment;
for(i = 0; i < 6; i++) {
/* today mark + focus */
static void MONTHCAL_PaintFocusAndCircle(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
{
- if((infoPtr->curSel.wMonth == infoPtr->todaysDate.wMonth) &&
- (infoPtr->curSel.wYear == infoPtr->todaysDate.wYear) &&
+ if((infoPtr->minSel.wMonth == infoPtr->todaysDate.wMonth) &&
+ (infoPtr->minSel.wYear == infoPtr->todaysDate.wYear) &&
!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
{
MONTHCAL_CircleDay(infoPtr, hdc, &infoPtr->todaysDate);
/* paint a calendar area */
static void MONTHCAL_PaintCalendar(const MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps, INT calIdx)
{
- INT prev_month, i, j;
+ const SYSTEMTIME *date = &infoPtr->calendars[calIdx].month;
+ INT prev_month, i, j, length;
+ RECT r, fill_bk_rect;
+ SYSTEMTIME st;
WCHAR buf[80];
HBRUSH hbr;
- RECT r, fill_bk_rect;
int mask;
- SYSTEMTIME st;
/* 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);
- hbr = CreateSolidBrush(infoPtr->monthbk);
+ hbr = CreateSolidBrush(infoPtr->colors[MCSC_MONTHBK]);
FillRect(hdc, &fill_bk_rect, hbr);
DeleteObject(hbr);
LineTo(hdc, infoPtr->calendars[calIdx].days.right - 3,
infoPtr->calendars[calIdx].title.bottom + infoPtr->textHeight + 1);
- prev_month = infoPtr->curSel.wMonth - 1;
+ prev_month = date->wMonth - 1;
if (prev_month == 0) prev_month = 12;
infoPtr->calendars[calIdx].wdays.left = infoPtr->calendars[calIdx].days.left =
/* 1. draw day abbreviations */
SelectObject(hdc, infoPtr->hFont);
- SetBkColor(hdc, infoPtr->monthbk);
- SetTextColor(hdc, infoPtr->trailingtxt);
+ SetBkColor(hdc, infoPtr->colors[MCSC_MONTHBK]);
+ SetTextColor(hdc, infoPtr->colors[MCSC_TRAILINGTEXT]);
/* rectangle to draw a single day abbreviation within */
r = infoPtr->calendars[calIdx].wdays;
r.right = r.left + infoPtr->width_increment;
{
SYSTEMTIME st_max;
- SetTextColor(hdc, infoPtr->trailingtxt);
+ SetTextColor(hdc, infoPtr->colors[MCSC_TRAILINGTEXT]);
/* draw prev month */
if (calIdx == 0)
{
MONTHCAL_GetMinDate(infoPtr, &st);
mask = 1 << (st.wDay-1);
+ length = MONTHCAL_MonthLength(prev_month, date->wYear);
- while(st.wDay <= MONTHCAL_MonthLength(prev_month, infoPtr->curSel.wYear))
+ while(st.wDay <= length)
{
MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[0] & mask, ps);
mask <<= 1;
/* draw next month */
if (calIdx == infoPtr->cal_num - 1)
{
- st = infoPtr->curSel;
+ st = *date;
st.wDay = 1;
MONTHCAL_GetNextMonth(&st);
MONTHCAL_GetMaxDate(infoPtr, &st_max);
}
/* 3. current month */
- SetTextColor(hdc, infoPtr->txt);
- st = infoPtr->curSel;
+ SetTextColor(hdc, infoPtr->colors[MCSC_TEXT]);
+ st = *date;
st.wDay = 1;
mask = 1;
- while(st.wDay <= MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear)) {
+ length = MONTHCAL_MonthLength(date->wMonth, date->wYear);
+ while(st.wDay <= length)
+ {
MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[1] & mask, ps);
mask <<= 1;
st.wDay++;
MONTHCAL_PaintTodayTitle(infoPtr, hdc, ps);
/* navigation buttons */
- MONTHCAL_PaintButton(infoPtr, hdc, FALSE);
- MONTHCAL_PaintButton(infoPtr, hdc, TRUE);
+ MONTHCAL_PaintButton(infoPtr, hdc, DIRECTION_BACKWARD);
+ MONTHCAL_PaintButton(infoPtr, hdc, DIRECTION_FORWARD);
/* restore context */
SetBkColor(hdc, old_bk_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->calendars[0].title.left;
- lpRect->top = infoPtr->calendars[0].title.top;
- lpRect->right = infoPtr->calendars[0].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");
+ 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;
- }
-
- return -1;
-}
+ TRACE("%p, %d: color %08x\n", infoPtr, index, color);
+ if (index > MCSC_TRAILINGTEXT) return -1;
-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;
- }
+ prev = infoPtr->colors[index];
+ infoPtr->colors[index] = color;
InvalidateRect(infoPtr->hwndSelf, NULL, index == MCSC_BACKGROUND ? TRUE : FALSE);
return prev;
}
-
static LRESULT
MONTHCAL_GetMonthDelta(const MONTHCAL_INFO *infoPtr)
{
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;
}
static LRESULT
MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
{
- SYSTEMTIME prev = infoPtr->curSel;
+ SYSTEMTIME prev = infoPtr->minSel;
+ WORD day;
TRACE("%p\n", curSel);
if(!curSel) 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;
/* 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;
- /* note that infoPtr->curSel isn't updated yet */
- MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->curSel, &r_prev);
+ prev.wDay = day;
+ MONTHCAL_CalcPosFromDay(infoPtr, &prev, &r_prev);
MONTHCAL_CalcPosFromDay(infoPtr, curSel, &r_new);
InvalidateRect(infoPtr->hwndSelf, &r_prev, FALSE);
else
InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
- infoPtr->curSel = *curSel;
- infoPtr->calendars[0].month = *curSel;
-
return TRUE;
}
infoPtr->minSel = range[1];
infoPtr->maxSel = range[0];
}
- infoPtr->curSel = infoPtr->minSel;
infoPtr->calendars[0].month = infoPtr->minSel;
/* update day of week */
MONTHCAL_CalculateDayOfWeek(&infoPtr->minSel, TRUE);
MONTHCAL_CalculateDayOfWeek(&infoPtr->maxSel, TRUE);
- MONTHCAL_CalculateDayOfWeek(&infoPtr->curSel, TRUE);
/* redraw if bounds changed */
/* FIXME: no actual need to redraw everything */
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)
{
INT day, wday, wnum, calIdx;
+ MCHITTESTINFO htinfo;
SYSTEMTIME ht_month;
UINT x, y;
x = lpht->pt.x;
y = lpht->pt.y;
- memset(&lpht->st, 0, 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,
if (calIdx == -1)
{
if (PtInRect(&infoPtr->todayrect, lpht->pt))
- lpht->uHit = MCHT_TODAYLINK;
+ {
+ htinfo.uHit = MCHT_TODAYLINK;
+ htinfo.rc = infoPtr->todayrect;
+ }
else
/* outside of calendar area? What's left must be background :-) */
- lpht->uHit = MCHT_CALENDARBK;
+ htinfo.uHit = MCHT_CALENDARBK;
- return lpht->uHit;
+ return fill_hittest_info(&htinfo, lpht);
}
ht_month = infoPtr->calendars[calIdx].month;
two calendars have buttons */
if (calIdx == 0 && PtInRect(&infoPtr->titlebtnprev, lpht->pt))
{
- lpht->uHit = MCHT_TITLEBTNPREV;
+ htinfo.uHit = MCHT_TITLEBTNPREV;
+ htinfo.rc = infoPtr->titlebtnprev;
}
else if (PtInRect(&infoPtr->titlebtnnext, lpht->pt))
{
- lpht->uHit = MCHT_TITLEBTNNEXT;
+ htinfo.uHit = MCHT_TITLEBTNNEXT;
+ htinfo.rc = infoPtr->titlebtnnext;
}
else if (PtInRect(&infoPtr->calendars[calIdx].titlemonth, lpht->pt))
{
- lpht->uHit = MCHT_TITLEMONTH;
+ htinfo.uHit = MCHT_TITLEMONTH;
+ htinfo.rc = infoPtr->calendars[calIdx].titlemonth;
+ htinfo.iOffset = calIdx;
}
else if (PtInRect(&infoPtr->calendars[calIdx].titleyear, lpht->pt))
{
- lpht->uHit = MCHT_TITLEYEAR;
+ htinfo.uHit = MCHT_TITLEYEAR;
+ htinfo.rc = infoPtr->calendars[calIdx].titleyear;
+ htinfo.iOffset = calIdx;
}
else
- lpht->uHit = MCHT_TITLE;
+ {
+ htinfo.uHit = MCHT_TITLE;
+ htinfo.rc = infoPtr->calendars[calIdx].title;
+ htinfo.iOffset = calIdx;
+ }
- return lpht->uHit;
+ 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))
{
- lpht->uHit = MCHT_CALENDARDAY;
- lpht->st.wYear = ht_month.wYear;
- lpht->st.wMonth = (day < 1) ? ht_month.wMonth -1 : ht_month.wMonth;
- lpht->st.wDay = (day < 1) ?
+ 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))
{
- lpht->uHit = MCHT_CALENDARWEEKNUM;
- lpht->st.wYear = ht_month.wYear;
+ htinfo.uHit = MCHT_CALENDARWEEKNUM;
+ htinfo.st.wYear = ht_month.wYear;
+ htinfo.iOffset = calIdx;
- if (day < 1) {
- lpht->st.wMonth = ht_month.wMonth - 1;
+ 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)) {
- lpht->st.wMonth = ht_month.wMonth + 1;
+ 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
- lpht->st.wMonth = ht_month.wMonth;
-
- if (day < 1) {
- lpht->st.wDay = MONTHCAL_MonthLength(ht_month.wMonth-1, ht_month.wYear) - day;
- }
- else if (day > MONTHCAL_MonthLength(ht_month.wMonth, ht_month.wYear)) {
- lpht->st.wDay = day - MONTHCAL_MonthLength(ht_month.wMonth, ht_month.wYear);
+ {
+ htinfo.st.wMonth = ht_month.wMonth;
+ htinfo.st.wDay = day;
}
- else
- lpht->st.wDay = day;
}
else if(PtInRect(&infoPtr->calendars[calIdx].days, lpht->pt))
{
- lpht->st.wYear = ht_month.wYear;
- lpht->st.wMonth = ht_month.wMonth;
+ htinfo.iOffset = calIdx;
+ htinfo.st.wYear = ht_month.wYear;
+ htinfo.st.wMonth = ht_month.wMonth;
if (day < 1)
{
- lpht->uHit = 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(lpht->st.wMonth, lpht->st.wYear) + day;
}
else if (day > MONTHCAL_MonthLength(ht_month.wMonth, ht_month.wYear))
{
- lpht->uHit = MCHT_CALENDARDATENEXT;
- MONTHCAL_GetNextMonth(&lpht->st);
- lpht->st.wDay = day - MONTHCAL_MonthLength(ht_month.wMonth, ht_month.wYear);
+ htinfo.uHit = MCHT_CALENDARDATENEXT;
+ MONTHCAL_GetNextMonth(&htinfo.st);
+ htinfo.st.wDay = day - MONTHCAL_MonthLength(ht_month.wMonth, ht_month.wYear);
}
- else {
- lpht->uHit = 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 */
- MONTHCAL_CalculateDayOfWeek(&lpht->st, TRUE);
+ MONTHCAL_CalculateDayOfWeek(&htinfo.st, TRUE);
}
- return lpht->uHit;
+ return fill_hittest_info(&htinfo, lpht);
}
/* MCN_GETDAYSTATE notification helper */
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);
}
}
-static void MONTHCAL_GoToPrevNextMonth(MONTHCAL_INFO *infoPtr, BOOL prev)
+/* no valid range check performed */
+static void MONTHCAL_Scroll(MONTHCAL_INFO *infoPtr, INT delta)
{
- SYSTEMTIME st = infoPtr->curSel;
+ INT i, selIdx = -1;
- TRACE("%s\n", prev ? "prev" : "next");
-
- if(prev) MONTHCAL_GetPrevMonth(&st); else MONTHCAL_GetNextMonth(&st);
+ 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;
- if(!MONTHCAL_IsDateInValidRange(infoPtr, &st, FALSE)) return;
+ MONTHCAL_GetMonth(&infoPtr->calendars[i].month, delta);
+ }
+ /* selection is always shifted to first calendar */
if(infoPtr->dwStyle & MCS_MULTISELECT)
{
SYSTEMTIME range[2];
- range[0] = infoPtr->minSel;
- range[1] = infoPtr->maxSel;
-
- if(prev)
- {
- MONTHCAL_GetPrevMonth(&range[0]);
- MONTHCAL_GetPrevMonth(&range[1]);
- }
- else
- {
- MONTHCAL_GetNextMonth(&range[0]);
- MONTHCAL_GetNextMonth(&range[1]);
- }
-
+ 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_GetMonth(&st, delta - selIdx);
MONTHCAL_SetCurSel(infoPtr, &st);
+ }
+}
- MONTHCAL_NotifyDayState(infoPtr);
+static void MONTHCAL_GoToMonth(MONTHCAL_INFO *infoPtr, enum nav_direction direction)
+{
+ INT delta = infoPtr->delta ? infoPtr->delta : infoPtr->cal_num;
+ SYSTEMTIME st;
+
+ TRACE("%s\n", direction == DIRECTION_BACKWARD ? "back" : "fwd");
+ /* 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);
+ }
+
+ if(!MONTHCAL_IsDateInValidRange(infoPtr, &st, FALSE)) return;
+
+ MONTHCAL_Scroll(infoPtr, direction == DIRECTION_BACKWARD ? -delta : delta);
+ MONTHCAL_NotifyDayState(infoPtr);
MONTHCAL_NotifySelectionChange(infoPtr);
}
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;
}
/* 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->calendars[0].titleyear.left + 3, infoPtr->titlebtnnext.top,
- infoPtr->calendars[0].titleyear.right - infoPtr->calendars[0].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->calendars[0].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_GoToPrevNextMonth(infoPtr, FALSE);
+ 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_GoToPrevNextMonth(infoPtr, TRUE);
+ 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;
if((hit & MCHT_CALENDARDATE) == MCHT_CALENDARDATE)
{
- SYSTEMTIME sel = infoPtr->curSel;
+ SYSTEMTIME sel = infoPtr->minSel;
/* will be invalidated here */
MONTHCAL_SetCurSel(infoPtr, &ht.st);
switch(id) {
case MC_PREVNEXTMONTHTIMER:
- if(infoPtr->status & MC_NEXTPRESSED) MONTHCAL_GoToPrevNextMonth(infoPtr, FALSE);
- if(infoPtr->status & MC_PREVPRESSED) MONTHCAL_GoToPrevNextMonth(infoPtr, TRUE);
+ 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:
if (!GetClipBox(hdc, &rc)) return FALSE;
/* fill background */
- hbr = CreateSolidBrush (infoPtr->bk);
+ hbr = CreateSolidBrush (infoPtr->colors[MCSC_BACKGROUND]);
FillRect(hdc, &rc, hbr);
DeleteObject(hbr);
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->monthdayState = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE));
if (!infoPtr->monthdayState) goto fail;
- 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;
+ 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->minSel = infoPtr->todaysDate;
infoPtr->maxSel = infoPtr->todaysDate;
- infoPtr->curSel = infoPtr->todaysDate;
infoPtr->calendars[0].month = infoPtr->todaysDate;
infoPtr->isUnicode = TRUE;
{
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 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)