📄 datetime.c
字号:
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:
case TWODIGITDAY:
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:
delta *= 12;
/* fall through */
case ONEDIGIT12HOUR:
case TWODIGIT12HOUR:
case ONEDIGIT24HOUR:
case TWODIGIT24HOUR:
date->wHour = wrap(date->wHour, delta, 0, 23);
break;
case ONEDIGITMINUTE:
case TWODIGITMINUTE:
date->wMinute = wrap(date->wMinute, delta, 0, 59);
break;
case ONEDIGITSECOND:
case TWODIGITSECOND:
date->wSecond = wrap(date->wSecond, delta, 0, 59);
break;
case FORMATCALLBACK:
FIXME ("Not implemented\n");
break;
}
/* FYI: On 1752/9/14 the calendar changed and England and the
* American colonies changed to the Gregorian calendar. This change
* involved having September 14th follow September 2nd. So no date
* algorithm works before that date.
*/
if (10000 * date->wYear + 100 * date->wMonth + date->wDay < 17520914) {
date->wYear = 1752;
date->wMonth = 9;
date->wDay = 14;
date->wSecond = 0;
date->wMinute = 0;
date->wHour = 0;
}
}
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];
LPCWSTR 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 = fld_d2W;
break;
case INVALIDFULLYEAR:
case FULLYEAR:
bufptr = fld_d4W;
break;
case THREECHARDAY:
bufptr = fld_day3;
break;
case FULLDAY:
bufptr = fld_day;
break;
case THREECHARMONTH:
bufptr = fld_mon3;
break;
case FULLMONTH:
bufptr = fld_mon;
break;
case ONELETTERAMPM:
bufptr = fld_am1;
break;
case TWOLETTERAMPM:
bufptr = fld_am2;
break;
default:
bufptr = fld_d1W;
break;
}
}
GetTextExtentPoint32W (hdc, bufptr, strlenW(bufptr), &size);
*fieldWidthPtr = size.cx;
}
static void
DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
{
int i,prevright;
RECT *field;
RECT *rcDraw = &infoPtr->rcDraw;
RECT *calbutton = &infoPtr->calbutton;
RECT *checkbox = &infoPtr->checkbox;
SIZE size;
COLORREF oldTextColor;
SHORT fieldWidth = 0;
/* draw control edge */
TRACE("\n");
if (infoPtr->dateValid) {
HFONT oldFont = SelectObject (hdc, infoPtr->hFont);
INT oldBkMode = SetBkMode (hdc, TRANSPARENT);
WCHAR txt[80];
DATETIME_ReturnTxt (infoPtr, 0, txt, sizeof(txt)/sizeof(txt[0]));
GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size);
rcDraw->bottom = size.cy + 2;
prevright = checkbox->right = ((infoPtr->dwStyle & DTS_SHOWNONE) ? 18 : 2);
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 + fieldWidth;
field->top = rcDraw->top;
field->bottom = rcDraw->bottom;
prevright = field->right;
if (infoPtr->dwStyle & WS_DISABLED)
oldTextColor = SetTextColor (hdc, comctl32_color.clrGrayText);
else if ((infoPtr->haveFocus) && (i == infoPtr->select)) {
/* fill if focussed */
HBRUSH hbr = CreateSolidBrush (comctl32_color.clrActiveCaption);
FillRect(hdc, field, hbr);
DeleteObject (hbr);
oldTextColor = SetTextColor (hdc, comctl32_color.clrWindow);
}
else
oldTextColor = SetTextColor (hdc, comctl32_color.clrWindowText);
/* draw the date text using the colour set above */
DrawTextW (hdc, txt, strlenW(txt), field, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
SetTextColor (hdc, oldTextColor);
}
SetBkMode (hdc, oldBkMode);
SelectObject (hdc, oldFont);
}
if (!(infoPtr->dwStyle & DTS_UPDOWN)) {
DrawFrameControl(hdc, calbutton, DFC_SCROLL,
DFCS_SCROLLDOWN | (infoPtr->bCalDepressed ? DFCS_PUSHED : 0) |
(infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
}
}
static INT
DATETIME_HitTest (DATETIME_INFO *infoPtr, POINT pt)
{
int i;
TRACE ("%d, %d\n", pt.x, pt.y);
if (PtInRect (&infoPtr->calbutton, pt)) return DTHT_MCPOPUP;
if (PtInRect (&infoPtr->checkbox, pt)) return DTHT_CHECKBOX;
for (i=0; i < infoPtr->nrFields; i++) {
if (PtInRect (&infoPtr->fieldRect[i], pt)) return i;
}
return DTHT_NONE;
}
static LRESULT
DATETIME_LButtonDown (DATETIME_INFO *infoPtr, WORD wKey, INT x, INT y)
{
POINT pt;
int old, new;
pt.x = x;
pt.y = y;
old = infoPtr->select;
new = DATETIME_HitTest (infoPtr, pt);
/* FIXME: might be conditions where we don't want to update infoPtr->select */
infoPtr->select = new;
SetFocus(infoPtr->hwndSelf);
if (infoPtr->select == DTHT_MCPOPUP) {
RECT rcMonthCal;
SendMessageW(infoPtr->hMonthCal, MCM_GETMINREQRECT, 0, (LPARAM)&rcMonthCal);
/* FIXME: button actually is only depressed during dropdown of the */
/* calendar control and when the mouse is over the button window */
infoPtr->bCalDepressed = TRUE;
/* recalculate the position of the monthcal popup */
if(infoPtr->dwStyle & DTS_RIGHTALIGN)
infoPtr->monthcal_pos.x = infoPtr->calbutton.left -
(rcMonthCal.right - rcMonthCal.left);
else
/* FIXME: this should be after the area reserved for the checkbox */
infoPtr->monthcal_pos.x = infoPtr->rcDraw.left;
infoPtr->monthcal_pos.y = infoPtr->rcClient.bottom;
ClientToScreen (infoPtr->hwndSelf, &(infoPtr->monthcal_pos));
SetWindowPos(infoPtr->hMonthCal, 0, infoPtr->monthcal_pos.x,
infoPtr->monthcal_pos.y, rcMonthCal.right - rcMonthCal.left,
rcMonthCal.bottom - rcMonthCal.top, 0);
if(IsWindowVisible(infoPtr->hMonthCal)) {
ShowWindow(infoPtr->hMonthCal, SW_HIDE);
} else {
SYSTEMTIME *lprgSysTimeArray = &infoPtr->date;
TRACE("update calendar %04d/%02d/%02d\n",
lprgSysTimeArray->wYear, lprgSysTimeArray->wMonth, lprgSysTimeArray->wDay);
SendMessageW(infoPtr->hMonthCal, MCM_SETCURSEL, 0, (LPARAM)(&infoPtr->date));
ShowWindow(infoPtr->hMonthCal, SW_SHOW);
}
TRACE ("dt:%p mc:%p mc parent:%p, desktop:%p\n",
infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hwndNotify, GetDesktopWindow ());
DATETIME_SendSimpleNotify (infoPtr, DTN_DROPDOWN);
}
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
return 0;
}
static LRESULT
DATETIME_LButtonUp (DATETIME_INFO *infoPtr, WORD wKey)
{
if(infoPtr->bCalDepressed) {
infoPtr->bCalDepressed = FALSE;
InvalidateRect(infoPtr->hwndSelf, &(infoPtr->calbutton), TRUE);
}
return 0;
}
static LRESULT
DATETIME_Paint (DATETIME_INFO *infoPtr, HDC hdc)
{
if (!hdc) {
PAINTSTRUCT ps;
hdc = BeginPaint (infoPtr->hwndSelf, &ps);
DATETIME_Refresh (infoPtr, hdc);
EndPaint (infoPtr->hwndSelf, &ps);
} else {
DATETIME_Refresh (infoPtr, hdc);
}
return 0;
}
static LRESULT
DATETIME_Button_Command (DATETIME_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
{
if( HIWORD(wParam) == BN_CLICKED) {
DWORD state = SendMessageW((HWND)lParam, BM_GETCHECK, 0, 0);
infoPtr->dateValid = (state == BST_CHECKED);
InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
}
return 0;
}
static LRESULT
DATETIME_Command (DATETIME_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
{
TRACE("hwndbutton = %p\n", infoPtr->hwndCheckbut);
if(infoPtr->hwndCheckbut == (HWND)lParam)
return DATETIME_Button_Command(infoPtr, wParam, lParam);
return 0;
}
static LRESULT
DATETIME_Enable (DATETIME_INFO *infoPtr, BOOL bEnable)
{
TRACE("%p %s\n", infoPtr, bEnable ? "TRUE" : "FALSE");
if (bEnable)
infoPtr->dwStyle &= ~WS_DISABLED;
else
infoPtr->dwStyle |= WS_DISABLED;
return 0;
}
static LRESULT
DATETIME_EraseBackground (DATETIME_INFO *infoPtr, HDC hdc)
{
HBRUSH hBrush, hSolidBrush = NULL;
RECT rc;
if (infoPtr->dwStyle & WS_DISABLED)
hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrBtnFace);
else
{
hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLOREDIT,
(WPARAM)hdc, (LPARAM)infoPtr->hwndSelf);
if (!hBrush)
hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrWindow);
}
GetClientRect (infoPtr->hwndSelf, &rc);
FillRect (hdc, &rc, hBrush);
if (hSolidBrush)
DeleteObject(hSolidBrush);
return -1;
}
static LRESULT
DATETIME_Notify (DATETIME_INFO *infoPtr, int idCtrl, LPNMHDR lpnmh)
{
TRACE ("Got notification %x from %p\n", lpnmh->code, lpnmh->hwndFrom);
TRACE ("info: %p %p %p\n", infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hUpdown);
if (lpnmh->code == MCN_SELECT) {
ShowWindow(infoPtr->hMonthCal, SW_HIDE);
infoPtr->dateValid = TRUE;
SendMessageW (infoPtr->hMonthCal, MCM_GETCURSEL, 0, (LPARAM)&infoPtr->date);
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;
}
static LRESULT
DATETIME_KeyDown (DATETIME_INFO *infoPtr, DWORD vkCode, LPARAM flags)
{
int fieldNum = infoPtr->select & DTHT_DATEFIELD;
int wrap = 0;
if (!(infoPtr->haveFocus)) return 0;
if ((fieldNum==0) && (infoPtr->select)) return 0;
if (infoPtr->select & FORMATCALLMASK) {
FIXME ("Callbacks not implemented yet\n");
}
if (vkCode >= '0' && vkCode <= '9') {
/* this is a somewhat simplified version of what Windows does */
SYSTEMTIME *date = &infoPtr->date;
switch (infoPtr->fieldspec[fieldNum]) {
case ONEDIGITYEAR:
case TWODIGITYEAR:
date->wYear = date->wYear - (date->wYear%100) +
(date->wYear%10)*10 + (vkCode-'0');
date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
date->wDay,date->wMonth,date->wYear);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case INVALIDFULLYEAR:
case FULLYEAR:
date->wYear = (date->wYear%1000)*10 + (vkCode-'0');
date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
date->wDay,date->wMonth,date->wYear);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGITMONTH:
case TWODIGITMONTH:
if ((date->wMonth%10) > 1 || (vkCode-'0') > 2)
date->wMonth = vkCode-'0';
else
date->wMonth = (date->wMonth%10)*10+vkCode-'0';
date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
date->wDay,date->wMonth,date->wYear);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGITDAY:
case TWODIGITDAY:
/* probably better checking here would help */
if ((date->wDay%10) >= 3 && (vkCode-'0') > 1)
date->wDay = vkCode-'0';
else
date->wDay = (date->wDay%10)*10+vkCode-'0';
date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
date->wDay,date->wMonth,date->wYear);
DATETIME_SendDateTimeChangeNotify (infoPtr);
break;
case ONEDIGIT12HOUR:
case TWODIGIT12HOUR:
if ((date->wHour%10) > 1 || (vkCode-'0') > 2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -