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.
This commit is contained in:
Duane Clark 2005-04-14 11:31:17 +00:00 committed by Alexandre Julliard
parent 44d2da9f5d
commit a6659d26d2
2 changed files with 166 additions and 18 deletions

View file

@ -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);

View file

@ -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;
}