From a6659d26d2a58a30ce02001f849828f40798cf57 Mon Sep 17 00:00:00 2001 From: Duane Clark Date: Thu, 14 Apr 2005 11:31:17 +0000 Subject: [PATCH] Monday is day number '1'. Set day of week when a day is selected in the calender. Use fixed width fields in datetime. DTS_TIMEFORMAT is a two bit field, so test accordingly. Reposition and resize the updown control when the datetime control is resized. Respond to updown inputs. --- dlls/comctl32/datetime.c | 169 ++++++++++++++++++++++++++++++++++++--- dlls/comctl32/monthcal.c | 15 ++-- 2 files changed, 166 insertions(+), 18 deletions(-) diff --git a/dlls/comctl32/datetime.c b/dlls/comctl32/datetime.c index 80cdb826d02..e5451cfea7e 100644 --- a/dlls/comctl32/datetime.c +++ b/dlls/comctl32/datetime.c @@ -82,6 +82,7 @@ typedef struct int *buflen; WCHAR textbuf[256]; POINT monthcal_pos; + int pendingUpdown; } DATETIME_INFO, *LPDATETIME_INFO; /* in monthcal.c */ @@ -256,7 +257,7 @@ DATETIME_SetFormatW (DATETIME_INFO *infoPtr, LPCWSTR lpszFormat) if (infoPtr->dwStyle & DTS_LONGDATEFORMAT) format_item = LOCALE_SLONGDATE; - else if (infoPtr->dwStyle & DTS_TIMEFORMAT) + else if ((infoPtr->dwStyle & DTS_TIMEFORMAT) == DTS_TIMEFORMAT) format_item = LOCALE_STIMEFORMAT; else /* DTS_SHORTDATEFORMAT */ format_item = LOCALE_SSHORTDATE; @@ -405,6 +406,19 @@ DATETIME_ReturnTxt (DATETIME_INFO *infoPtr, int count, LPWSTR result, int result TRACE ("arg%d=%x->[%s]\n", count, infoPtr->fieldspec[count], debugstr_w(result)); } +/* Offsets of days in the week to the weekday of january 1 in a leap year. */ +static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; + +/* returns the day in the week(0 == sunday, 6 == saturday) */ +/* day(1 == 1st, 2 == 2nd... etc), year is the year value */ +static int DATETIME_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year) +{ + year-=(month < 3); + + return((year + year/4 - year/100 + year/400 + + DayOfWeekTable[month-1] + day ) % 7); +} + static int wrap(int val, int delta, int minVal, int maxVal) { val += delta; @@ -428,12 +442,14 @@ DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta) case TWODIGITYEAR: case FULLYEAR: date->wYear = wrap(date->wYear, delta, 1752, 9999); + date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear); break; case ONEDIGITMONTH: case TWODIGITMONTH: case THREECHARMONTH: case FULLMONTH: date->wMonth = wrap(date->wMonth, delta, 1, 12); + date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear); delta = 0; /* fall through */ case ONEDIGITDAY: @@ -441,6 +457,7 @@ DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta) case THREECHARDAY: case FULLDAY: date->wDay = wrap(date->wDay, delta, 1, MONTHCAL_MonthLength(date->wMonth, date->wYear)); + date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear); break; case ONELETTERAMPM: case TWOLETTERAMPM: @@ -481,6 +498,92 @@ DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta) } +static void +DATETIME_ReturnFieldWidth (DATETIME_INFO *infoPtr, HDC hdc, int count, SHORT *fieldWidthPtr) +{ + /* fields are a fixed width, determined by the largest possible string */ + /* presumably, these widths should be language dependent */ + static const WCHAR fld_d1W[] = { '2', 0 }; + static const WCHAR fld_d2W[] = { '2', '2', 0 }; + static const WCHAR fld_d4W[] = { '2', '2', '2', '2', 0 }; + static const WCHAR fld_am1[] = { 'A', 0 }; + static const WCHAR fld_am2[] = { 'A', 'M', 0 }; + static const WCHAR fld_day[] = { 'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', 0 }; + static const WCHAR fld_day3[] = { 'W', 'e', 'd', 0 }; + static const WCHAR fld_mon[] = { 'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', 0 }; + static const WCHAR fld_mon3[] = { 'D', 'e', 'c', 0 }; + int spec; + WCHAR buffer[80], *bufptr; + SIZE size; + + TRACE ("%d,%d\n", infoPtr->nrFields, count); + if (count>infoPtr->nrFields || count < 0) { + WARN ("buffer overrun, have %d want %d\n", infoPtr->nrFields, count); + return; + } + + if (!infoPtr->fieldspec) return; + + spec = infoPtr->fieldspec[count]; + if (spec & DT_STRING) { + int txtlen = infoPtr->buflen[count]; + + if (txtlen > 79) + txtlen = 79; + memcpy (buffer, infoPtr->textbuf + (spec &~ DT_STRING), txtlen * sizeof(WCHAR)); + buffer[txtlen] = 0; + bufptr = buffer; + } + else { + switch (spec) { + case ONEDIGITDAY: + case ONEDIGIT12HOUR: + case ONEDIGIT24HOUR: + case ONEDIGITSECOND: + case ONEDIGITMINUTE: + case ONEDIGITMONTH: + case ONEDIGITYEAR: + /* these seem to use a two byte field */ + case TWODIGITDAY: + case TWODIGIT12HOUR: + case TWODIGIT24HOUR: + case TWODIGITSECOND: + case TWODIGITMINUTE: + case TWODIGITMONTH: + case TWODIGITYEAR: + bufptr = (WCHAR *)fld_d2W; + break; + case INVALIDFULLYEAR: + case FULLYEAR: + bufptr = (WCHAR *)fld_d4W; + break; + case THREECHARDAY: + bufptr = (WCHAR *)fld_day3; + break; + case FULLDAY: + bufptr = (WCHAR *)fld_day; + break; + case THREECHARMONTH: + bufptr = (WCHAR *)fld_mon3; + break; + case FULLMONTH: + bufptr = (WCHAR *)fld_mon; + break; + case ONELETTERAMPM: + bufptr = (WCHAR *)fld_am1; + break; + case TWOLETTERAMPM: + bufptr = (WCHAR *)fld_am2; + break; + default: + bufptr = (WCHAR *)fld_d1W; + break; + } + } + GetTextExtentPoint32W (hdc, bufptr, strlenW(bufptr), &size); + *fieldWidthPtr = size.cx; +} + static void DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc) { @@ -491,6 +594,7 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc) RECT *checkbox = &infoPtr->checkbox; SIZE size; COLORREF oldTextColor; + SHORT fieldWidth; /* draw control edge */ TRACE("\n"); @@ -509,9 +613,10 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc) for (i = 0; i < infoPtr->nrFields; i++) { DATETIME_ReturnTxt (infoPtr, i, txt, sizeof(txt)/sizeof(txt[0])); GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size); + DATETIME_ReturnFieldWidth (infoPtr, hdc, i, &fieldWidth); field = &infoPtr->fieldRect[i]; field->left = prevright; - field->right = prevright+size.cx; + field->right = prevright + fieldWidth; field->top = rcDraw->top; field->bottom = rcDraw->bottom; prevright = field->right; @@ -720,12 +825,17 @@ DATETIME_Notify (DATETIME_INFO *infoPtr, int idCtrl, LPNMHDR lpnmh) ShowWindow(infoPtr->hMonthCal, SW_HIDE); infoPtr->dateValid = TRUE; SendMessageW (infoPtr->hMonthCal, MCM_GETCURSEL, 0, (LPARAM)&infoPtr->date); - TRACE("got from calendar %04d/%02d/%02d\n", - infoPtr->date.wYear, infoPtr->date.wMonth, infoPtr->date.wDay); + TRACE("got from calendar %04d/%02d/%02d day of week %d\n", + infoPtr->date.wYear, infoPtr->date.wMonth, infoPtr->date.wDay, infoPtr->date.wDayOfWeek); SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_CHECKED, 0); InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); DATETIME_SendDateTimeChangeNotify (infoPtr); } + if ((lpnmh->hwndFrom == infoPtr->hUpdown) && (lpnmh->code == UDN_DELTAPOS)) { + LPNMUPDOWN lpnmud = (LPNMUPDOWN)lpnmh; + TRACE("Delta pos %d\n", lpnmud->iDelta); + infoPtr->pendingUpdown = lpnmud->iDelta; + } return 0; } @@ -789,6 +899,30 @@ DATETIME_KeyDown (DATETIME_INFO *infoPtr, DWORD vkCode, LPARAM flags) } +static LRESULT +DATETIME_VScroll (DATETIME_INFO *infoPtr, WORD wScroll) +{ + int fieldNum = infoPtr->select & DTHT_DATEFIELD; + + if ((SHORT)LOWORD(wScroll) != SB_THUMBPOSITION) return 0; + if (!(infoPtr->haveFocus)) return 0; + if ((fieldNum==0) && (infoPtr->select)) return 0; + + if (infoPtr->pendingUpdown >= 0) { + DATETIME_IncreaseField (infoPtr, fieldNum, 1); + DATETIME_SendDateTimeChangeNotify (infoPtr); + } + else { + DATETIME_IncreaseField (infoPtr, fieldNum, -1); + DATETIME_SendDateTimeChangeNotify (infoPtr); + } + + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + + return 0; +} + + static LRESULT DATETIME_KillFocus (DATETIME_INFO *infoPtr, HWND lostFocus) { @@ -874,13 +1008,23 @@ DATETIME_Size (DATETIME_INFO *infoPtr, WORD flags, INT width, INT height) TRACE("Height=%ld, Width=%ld\n", infoPtr->rcClient.bottom, infoPtr->rcClient.right); infoPtr->rcDraw = infoPtr->rcClient; - - /* set the size of the button that drops the calendar down */ - /* FIXME: account for style that allows button on left side */ - infoPtr->calbutton.top = infoPtr->rcDraw.top; - infoPtr->calbutton.bottom= infoPtr->rcDraw.bottom; - infoPtr->calbutton.left = infoPtr->rcDraw.right-15; - infoPtr->calbutton.right = infoPtr->rcDraw.right; + + if (infoPtr->dwStyle & DTS_UPDOWN) { + /* the updown control seems to ignore SetWindowPos messages */ + DestroyWindow(infoPtr->hUpdown); + /* hmmm... the updown control seems to ignore the width parameter */ + infoPtr->hUpdown = CreateUpDownControl (WS_CHILD | WS_BORDER | WS_VISIBLE, + infoPtr->rcClient.right-14, 0, 20, infoPtr->rcClient.bottom, + infoPtr->hwndSelf, 1, 0, 0, UD_MAXVAL, UD_MINVAL, 0); + } + else { + /* set the size of the button that drops the calendar down */ + /* FIXME: account for style that allows button on left side */ + infoPtr->calbutton.top = infoPtr->rcDraw.top; + infoPtr->calbutton.bottom= infoPtr->rcDraw.bottom; + infoPtr->calbutton.left = infoPtr->rcDraw.right-15; + infoPtr->calbutton.right = infoPtr->rcDraw.right; + } /* set enable/disable button size for show none style being enabled */ /* FIXME: these dimensions are completely incorrect */ @@ -1067,6 +1211,9 @@ DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_LBUTTONUP: return DATETIME_LButtonUp (infoPtr, (WORD)wParam); + case WM_VSCROLL: + return DATETIME_VScroll (infoPtr, (WORD)wParam); + case WM_CREATE: return DATETIME_Create (hwnd, (LPCREATESTRUCTW)lParam); diff --git a/dlls/comctl32/monthcal.c b/dlls/comctl32/monthcal.c index 36fed5c167c..f44af02ab4e 100644 --- a/dlls/comctl32/monthcal.c +++ b/dlls/comctl32/monthcal.c @@ -122,7 +122,7 @@ typedef struct } MONTHCAL_INFO, *LPMONTHCAL_INFO; -/* Offsets of days in the week to the weekday of january 1. */ +/* Offsets of days in the week to the weekday of january 1 in a leap year */ static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; @@ -187,17 +187,17 @@ void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to) Need to find out if we're on a DST place & adjust the clock accordingly. Above function assumes we have a valid data. Valid for year>1752; 1 <= d <= 31, 1 <= m <= 12. - 0 = Monday. + 0 = Sunday. */ -/* returns the day in the week(0 == monday, 6 == sunday) */ +/* returns the day in the week(0 == sunday, 6 == saturday) */ /* day(1 == 1st, 2 == 2nd... etc), year is the year value */ static int MONTHCAL_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year) { year-=(month < 3); return((year + year/4 - year/100 + year/400 + - DayOfWeekTable[month-1] + day - 1 ) % 7); + DayOfWeekTable[month-1] + day ) % 7); } /* From a given point, calculate the row (weekpos), column(daypos) @@ -537,7 +537,7 @@ static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, PAINTSTRUCT* ps) i = infoPtr->firstDay; for(j=0; j<7; j++) { - GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SABBREVDAYNAME1 + (i +j)%7, buf, countof(buf)); + GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf)); DrawTextW(hdc, buf, strlenW(buf), days, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); days->left+=infoPtr->width_increment; days->right+=infoPtr->width_increment; @@ -886,7 +886,7 @@ MONTHCAL_GetFirstDayOfWeek(MONTHCAL_INFO *infoPtr) /* sets the first day of the week that will appear in the control */ -/* 0 == Monday, 6 == Sunday */ +/* 0 == Sunday, 6 == Saturday */ /* FIXME: this needs to be implemented properly in MONTHCAL_Refresh() */ /* FIXME: we need more error checking here */ static LRESULT @@ -904,7 +904,7 @@ MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, LPARAM lParam) { GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, buf, countof(buf)); TRACE("%s %d\n", debugstr_w(buf), strlenW(buf)); - infoPtr->firstDay = atoiW(buf); + infoPtr->firstDay = (atoiW(buf)+1)%7; } return prev; } @@ -1238,6 +1238,7 @@ MONTHCAL_HitTest(MONTHCAL_INFO *infoPtr, LPARAM lParam) retval = MCHT_CALENDARDATE; lpht->st.wMonth = infoPtr->currentMonth; lpht->st.wDay = day; + lpht->st.wDayOfWeek = MONTHCAL_CalculateDayOfWeek(day,lpht->st.wMonth,lpht->st.wYear); } goto done; }