#include "stdafx.h" #include "optionsctrlimpl.h" #include "main.h" /* * OptionsCtrlImpl::DateTime */ ext::string OptionsCtrlImpl::DateTime::getDTFormatString(const ext::string& strFormat) { ext::string strOut, strPart; for (int i = 0; i < strFormat.length(); ++i) { if (strFormat[i] == '%' && i < strFormat.length() - 1) { ++i; bool bSharp = (strFormat[i] == '#'); ext::string strCode; if (bSharp && i < strFormat.length() - 1) ++i; switch (strFormat[i]) { case 'a': strCode = L"ddd"; break; case 'A': strCode = L"dddd"; break; case 'b': strCode = L"MMM"; break; case 'B': strCode = L"MMMM"; break; case 'd': strCode = bSharp ? L"d" : L"dd"; break; case 'H': strCode = bSharp ? L"H" : L"HH"; break; case 'I': strCode = bSharp ? L"h" : L"hh"; break; case 'm': strCode = bSharp ? L"M" : L"MM"; break; case 'M': strCode = bSharp ? L"m" : L"mm"; break; case 'p': strCode = L"tt"; // MEMO: seems not to work if current locale is 24-hour break; case 'y': strCode = L"yy"; break; case 'Y': strCode = L"yyyy"; break; case '%': strPart += L"%"; break; } if (!strCode.empty()) { if (!strPart.empty()) { strOut += L"'"; strOut += strPart; strOut += L"'"; strPart = L""; } strOut += strCode; } } else { strPart += strFormat[i]; if (strFormat[i] == '\'') strPart += L"'"; } } if (!strPart.empty()) { strOut += L"'"; strOut += strPart; strOut += L"'"; } return strOut; } SYSTEMTIME OptionsCtrlImpl::DateTime::toSystemTime(time_t timestamp) { SYSTEMTIME st; FILETIME ft; LONGLONG ll = Int32x32To64(timestamp, 10000000) + 116444736000000000; ft.dwLowDateTime = static_cast(ll); ft.dwHighDateTime = static_cast(ll >> 32); FileTimeToSystemTime(&ft, &st); return st; } time_t OptionsCtrlImpl::DateTime::fromSystemTime(const SYSTEMTIME& st) { FILETIME ft; LONGLONG ll; SystemTimeToFileTime(&st, &ft); ll = (static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; return static_cast((ll - 116444736000000000) / 10000000); } void OptionsCtrlImpl::DateTime::enableChildsDateTime() { if (m_bDisableChilds || m_bDisableChildsOnNone) { enableChilds(getChildEnable()); } } bool OptionsCtrlImpl::DateTime::getChildEnable() { return !m_bDisableChildsOnNone && m_bDisableChilds && m_bEnabled || m_bDisableChildsOnNone && !m_bNone && (!m_bDisableChilds || m_bEnabled); } time_t OptionsCtrlImpl::DateTime::getTimestampValue() { SYSTEMTIME st; if (SendMessage(m_hDateTimeWnd, DTM_GETSYSTEMTIME, 0, reinterpret_cast(&st)) == GDT_VALID) { return fromSystemTime(st); } else { return 24 * 60 * 60; } } bool OptionsCtrlImpl::DateTime::getTimestampNone() { if (!m_bAllowNone) { return false; } SYSTEMTIME st; return (SendMessage(m_hDateTimeWnd, DTM_GETSYSTEMTIME, 0, reinterpret_cast(&st)) != GDT_VALID); } ext::string OptionsCtrlImpl::DateTime::getCombinedText() { ext::string strTemp = m_strLabel; strTemp += L": "; if (m_bNone) strTemp += TranslateT("none"); else strTemp += utils::timestampToString(m_timestamp, m_strFormat.c_str()); return strTemp; } OptionsCtrlImpl::DateTime::DateTime(OptionsCtrlImpl* pCtrl, Item* pParent, const wchar_t* szLabel, const wchar_t* szFormat, time_t timestamp, DWORD dwFlags, INT_PTR dwData) : Item(pCtrl, itDateTime, szLabel, dwFlags, dwData), m_hDateTimeWnd(nullptr), m_strFormat(szFormat), m_timestamp(timestamp) { m_bDisableChildsOnNone = bool_(dwFlags & OCF_DISABLECHILDSONNONE); m_bAllowNone = bool_(dwFlags & OCF_ALLOWNONE); m_bNone = m_bAllowNone && bool_(dwFlags & OCF_NONE); m_strFormatDT = getDTFormatString(m_strFormat); m_pCtrl->insertItem(pParent, this, getCombinedText().c_str(), dwFlags, m_bEnabled ? siDateTime : siDateTimeG); if (pParent) { pParent->childAdded(this); } } void OptionsCtrlImpl::DateTime::onSelect() { if (!m_bEnabled || m_hDateTimeWnd) { return; } m_pCtrl->setNodeText(m_hItem, m_strLabel.c_str()); HFONT hTreeFront = reinterpret_cast(SendMessage(m_pCtrl->m_hTree, WM_GETFONT, 0, 0)); RECT r; if (m_pCtrl->getItemFreeRect(m_hItem, r)) { r.top -= 2; r.bottom += 2; if (r.left + 50 > r.right) { r.left = r.right - 50; } HWND hTempWnd; DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | (m_bAllowNone ? DTS_SHOWNONE : 0); if (hTempWnd = CreateWindowEx( WS_EX_CLIENTEDGE, DATETIMEPICK_CLASS, L"", dwStyle, r.left, r.top, r.right - r.left, r.bottom - r.top, m_pCtrl->m_hTree, reinterpret_cast(ccDateTime), g_hInst, nullptr)) { // restrict to dates a timestamp can hold (with 1 day less to avoid timezone issues) SYSTEMTIME stMinMax[2] = { toSystemTime(0x00000000 + 24 * 60 * 60), toSystemTime(0x7FFFFFFF - 24 * 60 * 60) }; SendMessage(hTempWnd, DTM_SETRANGE, GDTR_MIN | GDTR_MAX, reinterpret_cast(stMinMax)); // set format string SendMessage(hTempWnd, DTM_SETFORMAT, 0, reinterpret_cast(m_strFormatDT.c_str())); // set timestamp if (m_bAllowNone && m_bNone) { SendMessage(hTempWnd, DTM_SETSYSTEMTIME, GDT_NONE, 0); } else { SYSTEMTIME st = toSystemTime(m_timestamp); SendMessage(hTempWnd, DTM_SETSYSTEMTIME, GDT_VALID, reinterpret_cast(&st)); } SendMessage(hTempWnd, WM_SETFONT, reinterpret_cast(hTreeFront), MAKELPARAM(TRUE, 0)); m_hDateTimeWnd = hTempWnd; } } } void OptionsCtrlImpl::DateTime::onDeselect() { if (m_hDateTimeWnd) { RECT rToInvalidate; bool bValidRect = false; if (GetWindowRect(m_hDateTimeWnd, &rToInvalidate)) { ScreenToClient(m_pCtrl->m_hTree, reinterpret_cast(&rToInvalidate) + 0); ScreenToClient(m_pCtrl->m_hTree, reinterpret_cast(&rToInvalidate) + 1); bValidRect = true; } m_timestamp = getTimestampValue(); m_bNone = getTimestampNone(); m_pCtrl->setNodeText(m_hItem, getCombinedText().c_str()); DestroyWindow(m_hDateTimeWnd); m_hDateTimeWnd = nullptr; InvalidateRect(m_pCtrl->m_hTree, bValidRect ? &rToInvalidate : nullptr, TRUE); // enable childs? enableChildsDateTime(); } } void OptionsCtrlImpl::DateTime::onActivate() { if (!m_hDateTimeWnd) { onSelect(); } if (m_hDateTimeWnd) { SetFocus(m_hDateTimeWnd); } } void OptionsCtrlImpl::DateTime::onDateTimeChange() { if (m_hDateTimeWnd) { m_timestamp = getTimestampValue(); m_bNone = getTimestampNone(); // enable childs? enableChildsDateTime(); } } void OptionsCtrlImpl::DateTime::setEnabled(bool bEnable) { m_bEnabled = bEnable; m_pCtrl->setStateImage(m_hItem, bEnable ? siDateTime : siDateTimeG); enableChildsDateTime(); } void OptionsCtrlImpl::DateTime::childAdded(Item* pChild) { if (m_bDisableChilds || m_bDisableChildsOnNone) { pChild->setEnabled(getChildEnable()); } } void OptionsCtrlImpl::DateTime::setLabel(const wchar_t* szLabel) { m_strLabel = szLabel; // only if not editing (otherwise update when user finishes editing) if (!m_hDateTimeWnd) { m_pCtrl->setNodeText(m_hItem, getCombinedText().c_str()); } } bool OptionsCtrlImpl::DateTime::isNone() { if (m_hDateTimeWnd) { m_timestamp = getTimestampValue(); m_bNone = getTimestampNone(); } return m_bNone; } void OptionsCtrlImpl::DateTime::setNone() { if (!m_bAllowNone) { return; } m_bNone = true; if (m_hDateTimeWnd) { SendMessage(m_hDateTimeWnd, DTM_SETSYSTEMTIME, GDT_NONE, 0); } else { m_pCtrl->setNodeText(m_hItem, getCombinedText().c_str()); } // enable childs? enableChildsDateTime(); } time_t OptionsCtrlImpl::DateTime::getTimestamp() { if (m_hDateTimeWnd) { m_timestamp = getTimestampValue(); //m_bNone = getTimestampNone();/// @note : what was this supposed to be? } return m_timestamp; } void OptionsCtrlImpl::DateTime::setTimestamp(time_t timestamp) { m_bNone = false; m_timestamp = timestamp; if (m_hDateTimeWnd) { SYSTEMTIME st = toSystemTime(timestamp); SendMessage(m_hDateTimeWnd, DTM_SETSYSTEMTIME, GDT_VALID, reinterpret_cast(&st)); } else { m_pCtrl->setNodeText(m_hItem, getCombinedText().c_str()); } // enable childs? enableChildsDateTime(); } bool OptionsCtrlImpl::DateTime::isMonthCalVisible() { return (m_hDateTimeWnd && SendMessage(m_hDateTimeWnd, DTM_GETMONTHCAL, 0, 0)); }