windatepicker.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:16k
- // windatepicker.cpp
- //
- // Copyright (C) 2005, Chris Laurel <claurel@shatters.net>
- //
- // Windows front end for Celestia.
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public License
- // as published by the Free Software Foundation; either version 2
- // of the License, or (at your option) any later version.
- #include <windows.h>
- #include <commctrl.h>
- #include "celutil/basictypes.h"
- #include "celengine/astro.h"
- #include "celutil/util.h"
- #include "celutil/winutil.h"
- // DatePicker is a Win32 control for setting the date. It replaces the
- // date picker from commctl, adding a number of features appropriate
- // for astronomical applications:
- //
- // - The standard Windows date picker does not permit setting years
- // prior to 1752, the point that the US and UK switched to the
- // Gregorian calendar. Celestia's date picker allows setting any
- // year from -9999 to 9999.
- //
- // - Astronomical year conventions are used for dates before the
- // year 1. This means that the year 0 is not omitted, and the year
- // 2 BCE is entered as -1.
- //
- // - The first adoption of the Gregorian calendar was in 1582, when
- // days 5-14 were skipped in the month of October. All dates are
- // based on the initial 1582 reform, even though most countries
- // didn't adopt the Gregorian calendar until many years later.
- //
- // - No invalid date is permitted, including the skipped days in
- // October 1582.
- static char* Months[12] =
- {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
- enum DatePickerField
- {
- InvalidField = -1,
- DayField = 0,
- MonthField = 1,
- YearField = 2,
- NumFields = 3,
- };
- class DatePicker
- {
- public:
- DatePicker(HWND _hwnd, CREATESTRUCT& cs);
- ~DatePicker();
-
- LRESULT paint(HDC hdc);
- void redraw(HDC hdc);
- LRESULT keyDown(DWORD vkcode, LPARAM lParam);
- LRESULT killFocus(HWND lostFocus);
- LRESULT setFocus(HWND lostFocus);
- LRESULT enable(bool);
- LRESULT leftButtonDown(WORD key, int x, int y);
- LRESULT notify(int id, const NMHDR& nmhdr);
- LRESULT command(WPARAM wParam, LPARAM lParam);
- LRESULT resize(WORD flags, int width, int height);
- bool sendNotify(UINT code);
- bool notifyDateChanged();
- LRESULT setSystemTime(DWORD flag, SYSTEMTIME* sysTime);
- LRESULT getSystemTime(SYSTEMTIME* sysTime);
- LRESULT destroy();
- private:
- int getFieldWidth(DatePickerField field, HDC hdc);
- void incrementField();
- void decrementField();
- private:
- HWND hwnd;
- HWND parent;
- astro::Date date;
- DatePickerField selectedField;
- char textBuffer[64];
- HFONT hFont;
- DWORD style;
-
- bool haveFocus;
- bool firstDigit;
- RECT fieldRects[NumFields];
- RECT clientRect;
- };
- DatePicker::DatePicker(HWND _hwnd, CREATESTRUCT& cs) :
- hwnd(_hwnd),
- parent(cs.hwndParent),
- date(1970, 10, 25),
- selectedField(YearField),
- haveFocus(false),
- firstDigit(true)
- {
- textBuffer[0] = ' ';
- hFont = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
- clientRect.left = 0;
- clientRect.right = 0;
- clientRect.top = 0;
- clientRect.bottom = 0;
- }
- DatePicker::~DatePicker()
- {
- }
- LRESULT
- DatePicker::paint(HDC hdc)
- {
- PAINTSTRUCT ps;
- if (!hdc)
- {
- hdc = BeginPaint(hwnd, &ps);
- redraw(hdc);
- EndPaint(hwnd, &ps);
- }
- else
- {
- redraw(hdc);
- }
- return 0;
- }
- void
- DatePicker::redraw(HDC hdc)
- {
- RECT rect;
- GetClientRect(hwnd, &rect);
- SelectObject(hdc, hFont);
- SetTextColor(hdc, RGB(0, 0, 0));
- SetBkMode(hdc, TRANSPARENT);
- char dayBuf[32];
- char monthBuf[32];
- char yearBuf[32];
- bind_textdomain_codeset("celestia", CurrentCP());
- sprintf(dayBuf, "%02d", date.day);
- sprintf(monthBuf, "%s", _(Months[date.month - 1]));
- sprintf(yearBuf, "%5d", date.year);
- bind_textdomain_codeset("celestia", "UTF8");
- char* fieldText[NumFields];
- fieldText[DayField] = dayBuf;
- fieldText[MonthField] = monthBuf;
- fieldText[YearField] = yearBuf;
- int right = 2;
- for (unsigned int i = 0; i < NumFields; i++)
- {
- SIZE size;
- GetTextExtentPoint(hdc, fieldText[i], strlen(fieldText[i]), &size);
- int fieldWidth = getFieldWidth(DatePickerField(i), hdc);
- fieldRects[i].left = right;
- fieldRects[i].right = right + fieldWidth;
- fieldRects[i].top = rect.top;
- fieldRects[i].bottom = rect.bottom;
- right = fieldRects[i].right;
- if (i == selectedField && haveFocus)
- {
- RECT r = fieldRects[i];
- r.top = (clientRect.bottom - size.cy) / 2;
- r.bottom = r.top + size.cy + 1;
- HBRUSH hbrush = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
- FillRect(hdc, &r, hbrush);
- DeleteObject(hbrush);
-
- SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
- }
- else
- {
- SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
- }
- DrawText(hdc, fieldText[i], strlen(fieldText[i]), &fieldRects[i], DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
- }
- }
- static bool isLeapYear(unsigned int year)
- {
- if (year > 1582)
- {
- return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
- }
- else
- {
- return year % 4 == 0;
- }
- }
- static unsigned int daysInMonth(unsigned int month, unsigned int year)
- {
- static unsigned int daysPerMonth[12] =
- { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- if (month == 2)
- return isLeapYear(year) ? 29 : 28;
- else
- return daysPerMonth[month - 1];
- }
- static void clampToValidDate(astro::Date& date)
- {
- int days = (int) daysInMonth(date.month, date.year);
- if (date.day > days)
- date.day = days;
- // 10 days skipped in Gregorian calendar reform
- if (date.year == 1582 && date.month == 10 && date.day > 4 && date.day < 15)
- {
- if (date.day < 10)
- date.day = 4;
- else
- date.day = 15;
- }
- }
- LRESULT
- DatePicker::keyDown(DWORD vkcode, LPARAM flags)
- {
- if (!haveFocus)
- return 0;
- if (vkcode >= '0' && vkcode <= '9')
- {
- unsigned int digit = vkcode - '0';
- if (firstDigit)
- {
- switch (selectedField)
- {
- case DayField:
- if (digit != 0)
- date.day = digit;
- break;
- case MonthField:
- if (digit != 0)
- date.month = digit;
- break;
- case YearField:
- if (digit != 0)
- date.year = digit;
- break;
- }
- firstDigit = false;
- }
- else
- {
- switch (selectedField)
- {
- case DayField:
- {
- unsigned int day = date.day * 10 + digit;
- if (day >= 10)
- firstDigit = true;
- if (day > daysInMonth(date.month, date.year))
- day = 1;
- date.day = day;
- }
- break;
-
- case MonthField:
- {
- unsigned int month = date.month * 10 + digit;
- if (month > 1)
- firstDigit = true;
- if (month > 12)
- month = 1;
- date.month = month;
- }
- break;
-
- case YearField:
- {
- unsigned int year = date.year * 10 + digit;
- if (year >= 1000)
- firstDigit = true;
- if (year <= 9999)
- date.year = year;
- }
- break;
- }
- }
- clampToValidDate(date);
- notifyDateChanged();
- }
- else if (vkcode == VK_SUBTRACT || vkcode == VK_OEM_MINUS)
- {
- if (selectedField == YearField)
- {
- date.year = -date.year;
- clampToValidDate(date);
- notifyDateChanged();
- }
- }
- else
- {
- firstDigit = true;
- switch (vkcode)
- {
- case VK_LEFT:
- if ((int) selectedField == 0)
- selectedField = DatePickerField((int) NumFields - 1);
- else
- selectedField = DatePickerField((int) selectedField - 1);
- break;
- case VK_RIGHT:
- if ((int) selectedField == (int) NumFields - 1)
- selectedField = DatePickerField(0);
- else
- selectedField = DatePickerField((int) selectedField + 1);
- break;
-
- case VK_UP:
- incrementField();
- notifyDateChanged();
- break;
- case VK_DOWN:
- decrementField();
- notifyDateChanged();
- break;
-
- default:
- break;
- }
- }
- InvalidateRect(hwnd, NULL, TRUE);
- return 0;
- }
- LRESULT
- DatePicker::leftButtonDown(WORD key, int x, int y)
- {
- POINT pt;
- pt.x = x;
- pt.y = y;
- if (PtInRect(&fieldRects[DayField], pt))
- selectedField = DayField;
- else if (PtInRect(&fieldRects[MonthField], pt))
- selectedField = MonthField;
- else if (PtInRect(&fieldRects[YearField], pt))
- selectedField = YearField;
- InvalidateRect(hwnd, NULL, TRUE);
-
- ::SetFocus(hwnd); // note that this is the Win32 API function, not the class method
- return 0;
- }
- LRESULT
- DatePicker::setFocus(HWND lostFocus)
- {
- if (!haveFocus)
- {
- sendNotify(NM_SETFOCUS);
- haveFocus = true;
- }
- firstDigit = true;
- InvalidateRect(hwnd, NULL, TRUE);
-
- return 0;
- }
- LRESULT
- DatePicker::killFocus(HWND lostFocus)
- {
- if (haveFocus)
- {
- sendNotify(NM_KILLFOCUS);
- haveFocus = false;
- }
- InvalidateRect(hwnd, NULL, TRUE);
- return 0;
- }
- LRESULT
- DatePicker::enable(bool b)
- {
- if (!b)
- style &= ~WS_DISABLED;
- else
- style |= WS_DISABLED;
- return 0;
- }
- LRESULT
- DatePicker::notify(int id, const NMHDR& nmhdr)
- {
- return 0;
- }
- LRESULT
- DatePicker::command(WPARAM, LPARAM)
- {
- return 0;
- }
- bool
- DatePicker::sendNotify(UINT code)
- {
- NMHDR nmhdr;
- ZeroMemory(&nmhdr, sizeof(nmhdr));
- nmhdr.hwndFrom = hwnd;
- nmhdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
- nmhdr.code = code;
- return SendMessage(parent, WM_NOTIFY,
- nmhdr.idFrom,
- reinterpret_cast<LPARAM>(&nmhdr)) ? true : false;
- }
- bool
- DatePicker::notifyDateChanged()
- {
- NMDATETIMECHANGE change;
- ZeroMemory(&change, sizeof(change));
- change.nmhdr.hwndFrom = hwnd;
- change.nmhdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
- change.nmhdr.code = DTN_DATETIMECHANGE;
- change.st.wYear = date.year;
- change.st.wMonth = date.month;
- change.st.wDay = date.day;
- return SendMessage(parent, WM_NOTIFY,
- change.nmhdr.idFrom,
- reinterpret_cast<LPARAM>(&change)) ? true : false;
- }
- int
- DatePicker::getFieldWidth(DatePickerField field, HDC hdc)
- {
- char* maxWidthText = "