XTPDatePickerControl.cpp
上传用户:szled88
上传日期:2015-04-09
资源大小:43957k
文件大小:54k
源码类别:

对话框与窗口

开发平台:

Visual C++

  1. // XTPDatePickerControl.cpp: implementation of the CXTPDatePickerControl class.
  2. //
  3. // This file is a part of the XTREME CALENDAR MFC class library.
  4. // (c)1998-2008 Codejock Software, All Rights Reserved.
  5. //
  6. // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
  7. // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
  8. // CONSENT OF CODEJOCK SOFTWARE.
  9. //
  10. // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
  11. // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
  12. // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
  13. // SINGLE COMPUTER.
  14. //
  15. // CONTACT INFORMATION:
  16. // support@codejock.com
  17. // http://www.codejock.com
  18. //
  19. /////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "Resource.h"
  22. #include "Common/XTPDrawHelpers.h"
  23. #include "Common/XTPVC50Helpers.h"
  24. #include "Common/XTPImageManager.h"
  25. #include "Common/XTPSystemHelpers.h"
  26. #include "XTPTopLevelWndMsgNotifier.h"
  27. #include "XTPCalendarUtils.h"
  28. #include "XTPDatePickerItemMonth.h"
  29. #include "XTPDatePickerPaintManager.h"
  30. #include "XTPDatePickerDaysCollection.h"
  31. #include "XTPDatePickerList.h"
  32. #include "XTPDatePickerItemDay.h"
  33. #include "XTPDatePickerControl.h"
  34. #include "XTPDatePickerNotifications.h"
  35. #ifdef _DEBUG
  36. #define new DEBUG_NEW
  37. #undef THIS_FILE
  38. static char THIS_FILE[] = __FILE__;
  39. #endif
  40. #pragma warning(disable: 4571) // warning C4571: catch(...) blocks compiled with /EHs do not catch or re-throw Structured Exceptions
  41. // Custom class name for the Date Picker control window
  42. const TCHAR XTP_DATEPICKERCTRL_CLASSNAME[] = _T("XTPDatePicker");
  43. //////////////////////////////////////////////////////////////////////////
  44. // CXTPDatePickerButtons
  45. int CXTPDatePickerButtons::GetVisibleButtonCount() const
  46. {
  47. int nCount = 0;
  48. for (int i = 0; i < (int)GetSize(); i++)
  49. {
  50. if (GetAt(i)->m_bVisible) nCount++;
  51. }
  52. return nCount;
  53. }
  54. CXTPDatePickerButton* CXTPDatePickerButtons::Find(int nID) const
  55. {
  56. for (int i = 0; i < (int)GetSize(); i++)
  57. {
  58. if (GetAt(i)->m_nID == nID)
  59. return GetAt(i);
  60. }
  61. return NULL;
  62. }
  63. CXTPDatePickerButton* CXTPDatePickerButtons::HitTest(CPoint point) const
  64. {
  65. for (int i = 0; i < (int)GetSize(); i++)
  66. {
  67. if (GetAt(i)->m_bVisible && GetAt(i)->m_rcButton.PtInRect(point))
  68. return GetAt(i);
  69. }
  70. return NULL;
  71. }
  72. //////////////////////////////////////////////////////////////////////////
  73. // XTP_DAYITEM_METRICS
  74. XTP_DAYITEM_METRICS::XTP_DAYITEM_METRICS()
  75. {
  76. clrForeground = 0;
  77. clrBackground = 0;
  78. }
  79. CFont* XTP_DAYITEM_METRICS::GetFont()
  80. {
  81. return &m_fntText;
  82. }
  83. void XTP_DAYITEM_METRICS::SetFont(CFont* pFont)
  84. {
  85. ASSERT_VALID(pFont);
  86. if (!pFont)
  87. return;
  88. // set new font
  89. LOGFONT lf;
  90. pFont->GetLogFont(&lf);
  91. m_fntText.DeleteObject();
  92. m_fntText.CreateFontIndirect(&lf);
  93. }
  94. CXTPDatePickerButton::CXTPDatePickerButton()
  95. {
  96. m_rcButton.SetRectEmpty();
  97. m_bVisible = TRUE;
  98. m_bPressed = FALSE;
  99. m_bHighlight = FALSE;
  100. m_nID = 0;
  101. }
  102. CString CXTPDatePickerButton::GetCaption()
  103. {
  104. if (m_strCaption.IsEmpty())
  105. return CXTPCalendarUtils::LoadString(m_nID);
  106. return m_strCaption;
  107. }
  108. void CXTPDatePickerButton::SetCaption(LPCTSTR pcszCaption)
  109. {
  110. m_strCaption = pcszCaption;
  111. }
  112. //////////////////////////////////////////////////////////////////////////////
  113. // CXTPDatePickerControl
  114. CXTPDatePickerControl::CXTPDatePickerControl()
  115. {
  116. m_pConnect = new CXTPNotifyConnection;
  117. RegisterWindowClass();
  118. m_pfnCallback = NULL;
  119. m_pCallbackParam = NULL;
  120. m_nLockUpdateCount = 0;
  121. m_lcidActiveLocale = CXTPCalendarUtils::GetActiveLCID();
  122. m_pPaintManager = NULL;
  123. SetTheme(NULL);// set default paint manager
  124. //SetTheme(new CXTPDatePickerThemeOffice2007());
  125. m_bAutoSize = TRUE;
  126. m_mouseMode = mouseNothing;
  127. m_nTimerID = 0;
  128. m_bIsModal = FALSE;
  129. m_nMaxSelectionDays = XTP_SELECTION_INFINITE;
  130. m_bSelectWeek = FALSE;
  131. m_bRightToLeft = FALSE;
  132. m_bShowWeekNumbers = FALSE;
  133. m_nRows = 1;
  134. m_nColumns = 1;
  135. m_nFirstDayOfWeek = 2;
  136. m_nFirstWeekOfYearDays = 1;
  137. m_nMonthDelta = 0;
  138. m_bHighlightToday = TRUE;
  139. m_bChanged = TRUE;
  140. m_dtToday = COleDateTime::GetCurrentTime();
  141. m_dtFirstMonth.SetDate(m_dtToday.GetYear(), m_dtToday.GetMonth(), 1);
  142. m_dtMinRange.SetStatus(COleDateTime::null);
  143. m_dtMaxRange.SetStatus(COleDateTime::null);
  144. m_rcControl.SetRectEmpty();
  145. m_rcGrid.SetRectEmpty();
  146. m_bShowNonMonthDays = TRUE;
  147. m_borderStyle = xtpDatePickerBorder3D;
  148. m_pButtonCaptured = NULL;
  149. AddButton(XTP_IDS_DATEPICKER_TODAY);
  150. AddButton(XTP_IDS_DATEPICKER_NONE);
  151. m_pListControl = NULL;
  152. m_pSelectedDays = new CXTPDatePickerDaysCollection(this);
  153. m_arMonthNames = new CString[12];
  154. m_arDayOfWeekNames = new CString[7];
  155. m_bAllowNoncontinuousSelection = TRUE;
  156. m_bMultiSelectionMode = FALSE;
  157. m_bDeleteOnFinalRelease = FALSE;
  158. InitNames();
  159. ClearFocus();
  160. Populate();
  161. //-----------------------------------------------------------------------
  162. XTPGetTopLevelWndMsgNotifier()->Advise(this, WM_TIMECHANGE);
  163. }
  164. CXTPDatePickerControl::~CXTPDatePickerControl()
  165. {
  166. XTPGetTopLevelWndMsgNotifier()->Unadvise(this);
  167. ClearMonths();
  168. if (m_pPaintManager)
  169. m_pPaintManager->SetControl(NULL);
  170. CMDTARGET_RELEASE(m_pPaintManager);
  171. if (m_pListControl)
  172. {
  173. m_pListControl->DestroyWindow();
  174. delete m_pListControl;
  175. }
  176. CMDTARGET_RELEASE(m_pSelectedDays);
  177. if (m_nTimerID != 0 && m_hWnd)
  178. KillTimer(m_nTimerID);
  179. DestroyWindow();
  180. for (int i = 0; i < GetButtonCount(); i++)
  181. delete m_arrButtons[i];
  182. delete[] m_arDayOfWeekNames;
  183. delete[] m_arMonthNames;
  184. CMDTARGET_RELEASE(m_pConnect);
  185. }
  186. void CXTPDatePickerControl::OnDestroy()
  187. {
  188. if (m_bIsModal)
  189. {
  190. if (ContinueModal()) // skip if EndModalLoop has already called
  191. {
  192. EndModalLoop(IDABORT);
  193. }
  194. }
  195. CWnd::OnDestroy();
  196. }
  197. void CXTPDatePickerControl::AddButton(UINT nID)
  198. {
  199. CXTPDatePickerButton* pButton = new CXTPDatePickerButton();
  200. pButton->m_nID = nID;
  201. m_arrButtons.Add(pButton);
  202. }
  203. BOOL CXTPDatePickerControl::IsTodayButtonVisible()
  204. {
  205. CXTPDatePickerButton* pButton = m_arrButtons.Find(XTP_IDS_DATEPICKER_TODAY);
  206. return pButton ? pButton->m_bVisible : FALSE;
  207. }
  208. BOOL CXTPDatePickerControl::IsNoneButtonVisible()
  209. {
  210. CXTPDatePickerButton* pButton = m_arrButtons.Find(XTP_IDS_DATEPICKER_NONE);
  211. return pButton ? pButton->m_bVisible : FALSE;
  212. }
  213. void CXTPDatePickerControl::SetTheme(CXTPDatePickerPaintManager* pPaintManager)
  214. {
  215. // set default
  216. if (!pPaintManager)
  217. pPaintManager = new CXTPDatePickerPaintManager();
  218. if (m_pPaintManager)
  219. m_pPaintManager->SetControl(NULL);
  220. CMDTARGET_RELEASE(m_pPaintManager);
  221. m_pPaintManager = pPaintManager;
  222. if (m_pPaintManager)
  223. {
  224. m_pPaintManager->SetControl(this);
  225. m_pPaintManager->RefreshMetrics();
  226. }
  227. _RedrawControl(FALSE);
  228. }
  229. void CXTPDatePickerControl::RedrawControl()
  230. {
  231. _RedrawControl(TRUE);
  232. }
  233. void CXTPDatePickerControl::_RedrawControl(BOOL bUpdateNow)
  234. {
  235. m_bChanged = TRUE;
  236. if (GetSafeHwnd() && (m_nLockUpdateCount == 0))
  237. {
  238. Invalidate(FALSE);
  239. if (bUpdateNow)
  240. {
  241. UpdateWindow();
  242. }
  243. }
  244. }
  245. BEGIN_MESSAGE_MAP(CXTPDatePickerControl, CWnd)
  246. //{{AFX_MSG_MAP(CXTPDatePickerControl)
  247. ON_WM_CREATE()
  248. ON_WM_ERASEBKGND()
  249. ON_WM_PAINT()
  250. ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
  251. ON_WM_LBUTTONDOWN()
  252. ON_WM_LBUTTONUP()
  253. ON_WM_LBUTTONDBLCLK()
  254. ON_WM_CAPTURECHANGED()
  255. ON_WM_CANCELMODE()
  256. ON_WM_MOUSEMOVE()
  257. ON_WM_TIMER()
  258. ON_WM_TIMECHANGE()
  259. ON_WM_SIZE()
  260. ON_WM_SYSCOLORCHANGE()
  261. ON_WM_KEYDOWN()
  262. ON_WM_SETCURSOR()
  263. ON_WM_SETFOCUS()
  264. ON_WM_KILLFOCUS()
  265. ON_WM_GETDLGCODE()
  266. ON_WM_DESTROY()
  267. ON_WM_ENABLE()
  268. //}}AFX_MSG_MAP
  269. ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave)
  270. END_MESSAGE_MAP()
  271. /////////////////////////////////////////////////////////////////////////////
  272. // CXTPDatePickerControl message handlers
  273. BOOL CXTPDatePickerControl::OnEraseBkgnd(CDC* /*pDC*/)
  274. {
  275. return TRUE;
  276. }
  277. int CXTPDatePickerControl::OnCreate(LPCREATESTRUCT lp)
  278. {
  279. int nRet = CWnd::OnCreate(lp);
  280. CXTPClientRect rc(this);
  281. AdjustLayout(rc);
  282. if (m_bRightToLeft)
  283. {
  284. SetLayoutRTL(TRUE);
  285. }
  286. return nRet;
  287. }
  288. void CXTPDatePickerControl::PreSubclassWindow()
  289. {
  290. CXTPClientRect rc(this);
  291. AdjustLayout(rc);
  292. }
  293. BOOL CXTPDatePickerControl::GoModal(const RECT& rect, CWnd* pParentWnd)
  294. {
  295. if (!pParentWnd)
  296. pParentWnd = AfxGetMainWnd();
  297. CRect rcScreen(rect);
  298. if (!::IsWindow(m_hWnd) && !CreateEx(WS_EX_TOOLWINDOW, XTP_DATEPICKERCTRL_CLASSNAME, NULL, pParentWnd ? WS_CHILD : WS_POPUP, rcScreen, pParentWnd, 0))
  299. return FALSE;
  300. // Enable this window
  301. EnableWindow(TRUE);
  302. CWnd* pFocusWnd = SetFocus();
  303. if (pParentWnd)
  304. {
  305. SetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT, 0);
  306. ModifyStyle(WS_CHILD, WS_POPUP);
  307. SetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT, (LONG_PTR)pParentWnd->m_hWnd);
  308. }
  309. SetWindowPos(&CWnd::wndTopMost, rcScreen.left, rcScreen.top, rcScreen.Width(), rcScreen.Height(), SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
  310. SetCapture();
  311. SendNotification(XTP_NC_DATEPICKERBEFOREGOMODAL);
  312. SendMessageToParent(XTP_NC_DATEPICKERBEFOREGOMODAL);
  313. m_bIsModal = TRUE;
  314. m_nFlags |= WF_CONTINUEMODAL;
  315. int nResult = m_nModalResult;
  316. if (ContinueModal())
  317. {
  318. // enter modal loop
  319. DWORD dwFlags = MLF_SHOWONIDLE;
  320. if (GetStyle() & DS_NOIDLEMSG)
  321. dwFlags |= MLF_NOIDLEMSG;
  322. nResult = RunModalLoop(dwFlags);
  323. }
  324. ReleaseCapture();
  325. DestroyWindow();
  326. m_bIsModal = FALSE;
  327. if (pFocusWnd && ::IsWindow(pFocusWnd->GetSafeHwnd()))
  328. pFocusWnd->SetFocus();
  329. return (nResult == IDOK);
  330. }
  331. CSize CXTPDatePickerControl::SetGridDimentions(CRect rcClient)
  332. {
  333. CWindowDC dc(GetOwner());
  334. CSize szMonth(m_pPaintManager->CalcMonthRect(&dc));
  335. szMonth.cy += 2;
  336. m_nRows = max(1, rcClient.Height() / szMonth.cy);
  337. m_nColumns = max(1, rcClient.Width() / szMonth.cx);
  338. if (m_dtMaxRange.GetStatus() == COleDateTime::valid)
  339. {
  340. int nMaxRangeMonths = (m_dtMaxRange.GetYear() * 12 + m_dtMaxRange.GetMonth()) -
  341. (m_dtFirstMonth.GetYear() * 12 + m_dtFirstMonth.GetMonth()) + 1;
  342. if (m_dtMinRange.GetStatus() == COleDateTime::valid)
  343. {
  344. int nTotalMaxRangeMonths = (m_dtMaxRange.GetYear() * 12 + m_dtMaxRange.GetMonth()) -
  345. (m_dtMinRange.GetYear() * 12 + m_dtMinRange.GetMonth()) + 1;
  346. while (m_nRows * m_nColumns > nTotalMaxRangeMonths)
  347. {
  348. if (m_nRows > 1)
  349. m_nRows--;
  350. else if (m_nColumns > 1)
  351. m_nColumns--;
  352. else
  353. break;
  354. }
  355. }
  356. if (m_nRows * m_nColumns > nMaxRangeMonths)
  357. {
  358. ShiftDate(m_dtFirstMonth, nMaxRangeMonths - m_nRows * m_nColumns);
  359. }
  360. if (m_dtMinRange.GetStatus() == COleDateTime::valid &&
  361. m_dtFirstMonth < m_dtMinRange)
  362. {
  363. m_dtFirstMonth = m_dtMinRange;
  364. while (m_nRows * m_nColumns > nMaxRangeMonths)
  365. {
  366. if (m_nRows > 1)
  367. m_nRows--;
  368. else if (m_nColumns > 1)
  369. m_nColumns--;
  370. else
  371. break;
  372. }
  373. }
  374. }
  375. return szMonth;
  376. }
  377. void CXTPDatePickerControl::AdjustLayout(CRect rcClient)
  378. {
  379. if (!GetSafeHwnd())
  380. return;
  381. if (m_lcidActiveLocale != CXTPCalendarUtils::GetActiveLCID())
  382. {
  383. m_lcidActiveLocale = CXTPCalendarUtils::GetActiveLCID();
  384. InitNames();
  385. }
  386. m_dtToday = COleDateTime::GetCurrentTime();
  387. m_rcControl = rcClient;
  388. CSize szMonth(0, 0);
  389. CRect rcMonth(0, 0, 0, 0);
  390. //get button size
  391. CSize szButton(CalcButtonSize());
  392. m_rcGrid.CopyRect(&m_rcControl);
  393. m_pPaintManager->DrawBorder(0, this, m_rcGrid, FALSE);
  394. if (m_arrButtons.GetVisibleButtonCount() > 0)
  395. m_rcGrid.bottom -= szButton.cy;
  396. if (!m_bAutoSize)
  397. {
  398. szMonth.cx = m_rcGrid.Width() / m_nColumns;
  399. szMonth.cy = m_rcGrid.Height() / m_nRows;
  400. }
  401. else
  402. {
  403. szMonth = SetGridDimentions(m_rcGrid);
  404. CSize szGrid (szMonth.cx * m_nColumns, szMonth.cy * m_nRows);
  405. int nXOffset = max(0, (m_rcGrid.left + m_rcGrid.right - szGrid.cx) / 2);
  406. int nYOffset = max(0, (m_rcGrid.top + m_rcGrid.bottom - szGrid.cy) / 2);
  407. m_rcGrid = CRect(CPoint(nXOffset, nYOffset), szGrid);
  408. ClearMonths();
  409. CreateMonthArray();
  410. } // else auto end
  411. CalcButtonBandRect();
  412. int nIndex = 0;
  413. for (int nRow = 0; nRow < m_nRows; nRow++)
  414. {
  415. for (int nCol = 0; nCol < m_nColumns; nCol++)
  416. {
  417. rcMonth = CRect(CPoint(m_rcGrid.left + nCol * szMonth.cx, m_rcGrid.top + nRow * szMonth.cy), szMonth);
  418. rcMonth.DeflateRect(1, 1);
  419. // get next month item
  420. CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nIndex);
  421. nIndex++;
  422. // adjust internal month layout
  423. pMonth->AdjustLayout(rcMonth, !m_bAutoSize);
  424. }
  425. }
  426. m_bChanged = TRUE;
  427. }
  428. void CXTPDatePickerControl::OnPaint()
  429. {
  430. CPaintDC dc(this); // device context for painting
  431. CXTPClientRect rc(this);
  432. // Check cached bitmap
  433. if (!m_bChanged && m_bmpCache.GetSafeHandle() != 0)
  434. {
  435. CXTPCompatibleDC memDC(&dc, &m_bmpCache);
  436. dc.BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY);
  437. }
  438. else
  439. {
  440. CDC memDC;
  441. memDC.CreateCompatibleDC(&dc);
  442. m_bmpCache.DeleteObject();
  443. m_bmpCache.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
  444. CBitmap* pOldBitmap = memDC.SelectObject(&m_bmpCache);
  445. OnDraw(&memDC);
  446. if (!IsWindowEnabled())
  447. {
  448. XTPImageManager()->DisableBitmap(memDC, rc, XTP_CALENDAR_DISABLED_COLOR_LIGHT, XTP_CALENDAR_DISABLED_COLOR_DARK);
  449. }
  450. dc.BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY);
  451. memDC.SelectObject(pOldBitmap);
  452. // update flag
  453. m_bChanged = FALSE;
  454. }
  455. }
  456. LRESULT CXTPDatePickerControl::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/)
  457. {
  458. CDC* pDC = CDC::FromHandle((HDC)wParam);
  459. if (pDC)
  460. {
  461. OnDraw(pDC);
  462. }
  463. return TRUE;
  464. }
  465. void CXTPDatePickerControl::OnDraw(CDC* pDC)
  466. {
  467. CXTPClientRect rcClient(this);
  468. // draw background
  469. m_pPaintManager->DrawBackground(pDC, rcClient);
  470. // draw all month items in the collection
  471. int nMonthCount = (int)m_arrMonths.GetSize();
  472. for (int nIndex = 0; nIndex < nMonthCount; nIndex++)
  473. {
  474. // get next month item
  475. CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nIndex);
  476. // draw it
  477. pMonth->Draw(pDC);
  478. }
  479. // draw today/none buttons
  480. DrawButtons(pDC);
  481. // draw border
  482. m_pPaintManager->DrawBorder(pDC, this, rcClient, TRUE);
  483. }
  484. UINT CXTPDatePickerControl::OnGetDlgCode()
  485. {
  486. return DLGC_WANTARROWS /*| DLGC_WANTTAB | DLGC_WANTALLKEYS*/;
  487. }
  488. void CXTPDatePickerControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  489. {
  490. #ifdef XTP_DATEPICKER_SITENOTIFY_KEY
  491. if (!XTP_DATEPICKER_SITENOTIFY_KEY(this, TRUE, nChar))
  492. return;
  493. #endif
  494. if (nChar == 0)
  495. return;
  496. if (nChar == VK_RETURN || nChar == VK_ESCAPE)
  497. {
  498. if (m_bIsModal)
  499. {
  500. if (ContinueModal()) // skip if EndModalLoop has already called
  501. {
  502. EndModalLoop(nChar == VK_RETURN ? IDOK : IDCANCEL);
  503. }
  504. return;
  505. }
  506. }
  507. else if (nChar == VK_LEFT || nChar == VK_RIGHT || nChar == VK_UP ||
  508. nChar == VK_DOWN || nChar == VK_PRIOR || nChar == VK_NEXT ||
  509. nChar == VK_HOME || nChar == VK_END ||
  510. nChar == VK_SPACE)
  511. {
  512. CXTPSelectionHelper _selector(this);
  513. BOOL bIsShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
  514. BOOL bIsCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0 || IsMultiSelectionMode();
  515. XTPDrawHelpers()->KeyToLayout(this, nChar);
  516. if (nChar == VK_RIGHT)
  517. {
  518. _selector.MoveFocus(stepDay, dirNext, bIsShift, bIsCtrl);
  519. }
  520. else if (nChar == VK_DOWN)
  521. {
  522. _selector.MoveFocus(stepWeek, dirNext, bIsShift, bIsCtrl);
  523. }
  524. else if (nChar == VK_NEXT && !bIsCtrl)
  525. {
  526. _selector.MoveFocus(stepMonth, dirNext, FALSE, FALSE);
  527. }
  528. else if (nChar == VK_NEXT && bIsCtrl)
  529. {
  530. _selector.MoveFocus(stepYear, dirNext, FALSE, FALSE);
  531. }
  532. //*****
  533. else if (nChar == VK_LEFT)
  534. {
  535. _selector.MoveFocus(stepDay, dirPrev, bIsShift, bIsCtrl);
  536. }
  537. else if (nChar == VK_UP)
  538. {
  539. _selector.MoveFocus(stepWeek, dirPrev, bIsShift, bIsCtrl);
  540. }
  541. else if (nChar == VK_PRIOR && !bIsCtrl)
  542. {
  543. _selector.MoveFocus(stepMonth, dirPrev, FALSE, FALSE);
  544. }
  545. else if (nChar == VK_PRIOR && bIsCtrl)
  546. {
  547. _selector.MoveFocus(stepYear, dirPrev, FALSE, FALSE);
  548. }
  549. //***
  550. else if (nChar == VK_HOME && !bIsCtrl)
  551. {
  552. _selector.MoveFocus(stepWeekBE, dirPrev, FALSE, FALSE);
  553. }
  554. else if (nChar == VK_HOME && bIsCtrl)
  555. {
  556. _selector.MoveFocus(stepMonthBE, dirPrev, FALSE, FALSE);
  557. }
  558. //***
  559. else if (nChar == VK_END && !bIsCtrl)
  560. {
  561. _selector.MoveFocus(stepWeekBE, dirNext, FALSE, FALSE);
  562. }
  563. else if (nChar == VK_END && bIsCtrl)
  564. {
  565. _selector.MoveFocus(stepMonthBE, dirNext, FALSE, FALSE);
  566. }
  567. //***
  568. else if (nChar == VK_SPACE && bIsCtrl)
  569. {
  570. _selector.SelUnselFocus();
  571. }
  572. //***
  573. _selector._TmpSaveFocus();
  574. m_nLockUpdateCount++;
  575. // fire selection changed
  576. SendNotification(XTP_NC_DATEPICKERSELECTIONCHANGED);
  577. SendMessageToParent(XTP_NC_DATEPICKER_SELECTION_CHANGED);
  578. //***
  579. _selector._TmpRestoreFocus();
  580. m_nLockUpdateCount--;
  581. //-------------------
  582. EnsureVisibleFocus();
  583. //--------------
  584. RedrawControl();
  585. }
  586. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  587. }
  588. void CXTPDatePickerControl::OnLButtonDown(UINT nFlags, CPoint point)
  589. {
  590. if (m_bIsModal && !m_rcControl.PtInRect(point))
  591. {
  592. if (ContinueModal()) // skip if EndModalLoop has already called
  593. {
  594. EndModalLoop(IDCANCEL);
  595. }
  596. return;
  597. }
  598. if (!m_bIsModal)
  599. {
  600. SetCapture();
  601. }
  602. SetFocus();
  603. CXTPDatePickerItemMonth* pMonth = HitTest(point);
  604. if (pMonth)
  605. {
  606. pMonth->OnLButtonDown(nFlags, point);
  607. }
  608. // process buttons
  609. m_pButtonCaptured = m_arrButtons.HitTest(point);
  610. ProcessButtons(point);
  611. CWnd::OnLButtonDown(nFlags, point);
  612. }
  613. void CXTPDatePickerControl::OnLButtonDblClk(UINT nFlags, CPoint point)
  614. {
  615. CXTPDatePickerItemMonth* pMonth = HitTest(point);
  616. if (pMonth)
  617. {
  618. pMonth->OnLButtonDown(nFlags, point);
  619. }
  620. m_pButtonCaptured = m_arrButtons.HitTest(point);
  621. ProcessButtons(point);
  622. CWnd::OnLButtonDblClk(nFlags, point);
  623. }
  624. void CXTPDatePickerControl::OnLButtonUp(UINT nFlags, CPoint point)
  625. {
  626. // kill timer
  627. if (m_nTimerID != 0)
  628. {
  629. KillTimer(m_nTimerID);
  630. m_nTimerID = 0;
  631. }
  632. // logic message processing
  633. if (m_mouseMode == mouseTrackingHeaderList)
  634. {
  635. // reset mouse mode
  636. m_mouseMode = mouseNothing;
  637. if (m_pListControl)
  638. {
  639. int nDelta = m_pListControl->GetMonthInterval();
  640. // destroy list control
  641. m_pListControl->DestroyWindow();
  642. delete m_pListControl;
  643. m_pListControl = NULL;
  644. // scroll on selected months count
  645. if (nDelta < 0)
  646. ScrollLeft(-nDelta);
  647. else if (nDelta > 0)
  648. ScrollRight(nDelta);
  649. }
  650. }
  651. else
  652. {
  653. // forward message to appropriate month
  654. CXTPDatePickerItemMonth* pMonth = HitTest(point);
  655. if (pMonth)
  656. {
  657. pMonth->OnLButtonUp(nFlags, point);
  658. }
  659. // Update selection
  660. BOOL bSelecting = m_mouseMode == mouseSelecting;
  661. BOOL bDeselecting = m_mouseMode == mouseDeselecting;
  662. if (bSelecting || bDeselecting)
  663. {
  664. int nDay = (m_dtLastClicked - m_dtFirstClicked).GetDays();
  665. for (; abs(nDay) >= 0; nDay += nDay > 0 ? -1 : 1)
  666. {
  667. COleDateTime dtSelect(m_dtFirstClicked);
  668. dtSelect += nDay;
  669. if (bDeselecting)
  670. {
  671. m_pSelectedDays->Remove(dtSelect);
  672. }
  673. else if (bSelecting && IsSelected(dtSelect))
  674. {
  675. m_pSelectedDays->Add(dtSelect);
  676. }
  677. if (nDay == 0)
  678. break;
  679. }
  680. // reset mouse mode
  681. m_mouseMode = mouseNothing;
  682. // fire selection changed
  683. SendNotification(XTP_NC_DATEPICKERSELECTIONCHANGED);
  684. SendMessageToParent(XTP_NC_DATEPICKER_SELECTION_CHANGED);
  685. _EndModalIfNeed();
  686. }
  687. }
  688. //release resources
  689. if (!m_bIsModal)
  690. ReleaseCapture();
  691. // process buttons
  692. m_pButtonCaptured = NULL;
  693. ProcessButtons(point);
  694. // reset mouse mode
  695. m_mouseMode = mouseNothing;
  696. CWnd::OnLButtonUp(nFlags, point);
  697. }
  698. void CXTPDatePickerControl::OnCaptureChanged(CWnd* pWnd)
  699. {
  700. // kill timer
  701. if (m_nTimerID != 0)
  702. {
  703. KillTimer(m_nTimerID);
  704. m_nTimerID = 0;
  705. }
  706. // logic message processing
  707. if (m_mouseMode == mouseTrackingHeaderList)
  708. {
  709. // reset mouse mode
  710. m_mouseMode = mouseNothing;
  711. if (m_pListControl)
  712. {
  713. if (m_pListControl->GetSafeHwnd())
  714. m_pListControl->DestroyWindow();
  715. delete m_pListControl;
  716. m_pListControl = NULL;
  717. }
  718. }
  719. m_pButtonCaptured = NULL;
  720. if (m_bIsModal)
  721. {
  722. if (ContinueModal()) // skip if EndModalLoop has already called
  723. {
  724. EndModalLoop(IDOK);
  725. }
  726. }
  727. CWnd::OnCaptureChanged(pWnd);
  728. }
  729. void CXTPDatePickerControl::OnCancelMode()
  730. {
  731. CWnd::OnCancelMode();
  732. }
  733. void CXTPDatePickerControl::OnMouseLeave()
  734. {
  735. TRACKMOUSEEVENT tre;
  736. tre.dwFlags = TME_CANCEL;
  737. tre.hwndTrack = this->m_hWnd;
  738. tre.dwHoverTime = HOVER_DEFAULT;
  739. tre.cbSize = sizeof(tre);
  740. _TrackMouseEvent(&tre);
  741. ProcessButtons(CPoint(-1, -1));
  742. }
  743. void CXTPDatePickerControl::OnMouseMove(UINT nFlags, CPoint point)
  744. {
  745. if (m_mouseMode == mouseTrackingHeaderList)
  746. {
  747. if (m_pListControl)
  748. {
  749. m_pListControl->OnMouseMove(nFlags, point);
  750. }
  751. }
  752. else
  753. {
  754. // forward message to appropriate month
  755. CXTPDatePickerItemMonth* pMonth = HitTest(point);
  756. if (pMonth)
  757. pMonth->OnMouseMove(nFlags, point);
  758. }
  759. ProcessButtons(point);
  760. // standard processing
  761. CWnd::OnMouseMove(nFlags, point);
  762. TRACKMOUSEEVENT tre;
  763. tre.dwFlags = TME_LEAVE;
  764. tre.hwndTrack = this->m_hWnd;
  765. tre.dwHoverTime = HOVER_DEFAULT;
  766. tre.cbSize = sizeof(tre);
  767. _TrackMouseEvent(&tre);
  768. // fire mouse move
  769. DWORD dwPoint = MAKELONG(point.x, point.y);
  770. SendNotification(XTP_NC_DATEPICKERMOUSEMOVE, dwPoint);
  771. }
  772. BOOL CXTPDatePickerControl::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/)
  773. {
  774. WNDCLASS wndcls;
  775. if (hInstance == NULL) hInstance = AfxGetInstanceHandle();
  776. if (!(::GetClassInfo(hInstance, XTP_DATEPICKERCTRL_CLASSNAME, &wndcls)))
  777. {
  778. // otherwise we need to register a new class
  779. wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  780. wndcls.lpfnWndProc = ::DefWindowProc;
  781. wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
  782. wndcls.hInstance = hInstance;
  783. wndcls.hIcon = NULL;
  784. wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
  785. wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  786. wndcls.lpszMenuName = NULL;
  787. wndcls.lpszClassName = XTP_DATEPICKERCTRL_CLASSNAME;
  788. if (!AfxRegisterClass(&wndcls))
  789. {
  790. AfxThrowResourceException();
  791. return FALSE;
  792. }
  793. }
  794. return TRUE;
  795. }
  796. BOOL CXTPDatePickerControl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
  797. {
  798. if (!CWnd::Create(XTP_DATEPICKERCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID, pContext))
  799. return FALSE;
  800. return TRUE;
  801. }
  802. void CXTPDatePickerControl::OnSize(UINT nType, int cx, int cy)
  803. {
  804. CWnd::OnSize(nType, cx, cy);
  805. CXTPClientRect rc(this);
  806. CRect rcClient(0, 0, 0, 0);
  807. this->GetClientRect(&rcClient);
  808. AdjustLayout(rcClient);
  809. }
  810. void CXTPDatePickerControl::ClearMonths()
  811. {
  812. // cleanup old month array
  813. int nOldMonthCount = (int)m_arrMonths.GetSize();
  814. for (int nMonth = 0; nMonth < nOldMonthCount; nMonth++)
  815. {
  816. CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nMonth);
  817. pMonth->InternalRelease();
  818. }
  819. m_arrMonths.RemoveAll();
  820. }
  821. void CXTPDatePickerControl::CreateMonthArray()
  822. {
  823. COleDateTime dtNextMonth(m_dtFirstMonth);
  824. for (int nRow = 0; nRow < m_nRows; nRow++)
  825. {
  826. for (int nCol = 0; nCol < m_nColumns; nCol++)
  827. {
  828. //int nIndex = nRow * m_nRows + nCol;
  829. // create next month item
  830. CXTPDatePickerItemMonth* pMonth = new CXTPDatePickerItemMonth(this, dtNextMonth, nRow, nCol);
  831. // add it to the array
  832. m_arrMonths.Add(pMonth);
  833. // go to the next month
  834. if (dtNextMonth.GetMonth() < 12)
  835. dtNextMonth.SetDate(dtNextMonth.GetYear(), dtNextMonth.GetMonth() + 1, 1);
  836. else
  837. dtNextMonth.SetDate(dtNextMonth.GetYear() + 1, 1, 1);
  838. }
  839. }
  840. // set first month and last month defaults
  841. int nMonthCount = (int)m_arrMonths.GetSize();
  842. if (nMonthCount > 0)
  843. {
  844. CXTPDatePickerItemMonth* pFirstMonth = m_arrMonths.GetAt(0);
  845. CXTPDatePickerItemMonth* pLastMonth = m_arrMonths.GetAt(nMonthCount - 1);
  846. // by default set show previous days for first month and show following days for last month
  847. pFirstMonth->SetShowDaysBefore(m_bShowNonMonthDays);
  848. pLastMonth->SetShowDaysAfter(m_bShowNonMonthDays);
  849. // set triangles showing
  850. pFirstMonth->SetShowScrolling(TRUE, pFirstMonth->GetShowRightScroll());
  851. CXTPDatePickerItemMonth* pLastMonthTopRow = m_arrMonths.GetAt(m_nColumns - 1);
  852. pLastMonthTopRow->SetShowScrolling(pLastMonthTopRow->GetShowLeftScroll(), TRUE);
  853. }
  854. }
  855. void CXTPDatePickerControl::Populate()
  856. {
  857. // cleanup old month array
  858. ClearMonths();
  859. // add all month items in the grid to the array
  860. // and set first month and last month defaults
  861. CreateMonthArray();
  862. // redraw control image
  863. if (!m_rcControl.IsRectEmpty())
  864. AdjustLayout(m_rcControl);
  865. _RedrawControl(FALSE);
  866. SendNotification(XTP_NC_DATEPICKERMONTHCHANGED);
  867. SendMessageToParent(XTP_NC_DATEPICKERMONTHCHANGED);
  868. }
  869. void CXTPDatePickerControl::GetDayMetrics(COleDateTime& dtDay, XTP_DAYITEM_METRICS* pDayMetics)
  870. {
  871. WPARAM wprmDay = (XTP_DATE_VALUE)(DATE)dtDay;
  872. SendNotification(XTP_NC_DATEPICKERGETDAYMETRICS, wprmDay, (LPARAM)pDayMetics);
  873. if (m_pfnCallback)
  874. {
  875. try
  876. {
  877. m_pfnCallback(this, dtDay, pDayMetics, m_pCallbackParam);
  878. }
  879. catch(...)
  880. {
  881. ASSERT(FALSE);
  882. }
  883. }
  884. }
  885. void CXTPDatePickerControl::SetGridSize(int nRows, int nCols)
  886. {
  887. m_nRows = nRows;
  888. m_nColumns = nCols;
  889. Populate();
  890. }
  891. void CXTPDatePickerControl::SetHighlightToday(BOOL bValue)
  892. {
  893. m_bHighlightToday = bValue;
  894. _RedrawControl(FALSE);
  895. }
  896. void CXTPDatePickerControl::SetShowWeekNumbers(BOOL bValue)
  897. {
  898. m_bShowWeekNumbers = bValue;
  899. AdjustLayout(m_rcControl);
  900. _RedrawControl(FALSE);
  901. }
  902. CSize CXTPDatePickerControl::CalcButtonSize() const
  903. {
  904. // get button size
  905. CWindowDC dc(GetDesktopWindow());
  906. CXTPFontDC fnt(&dc, m_pPaintManager->GetButtonFont());
  907. CSize szButton(0, 0);
  908. for (int i = 0; i < GetButtonCount(); i++)
  909. {
  910. CSize sz = dc.GetTextExtent(GetButton(i)->GetCaption());
  911. szButton.cx = max(szButton.cx, sz.cx + 12);
  912. szButton.cy = max(szButton.cy, sz.cy + 6);
  913. }
  914. return szButton;
  915. }
  916. void CXTPDatePickerControl::SetButtonRect()
  917. {
  918. CSize szButton(CalcButtonSize());
  919. int nGap = 10;
  920. int nButtonLen = szButton.cx + nGap;
  921. int nVisibleCount = m_arrButtons.GetVisibleButtonCount();
  922. int nLeft = m_rcGrid.CenterPoint().x - (nButtonLen * nVisibleCount - nGap)/2;
  923. for (int i = 0; i < GetButtonCount(); i++)
  924. {
  925. CXTPDatePickerButton* pButton = GetButton(i);
  926. if (!pButton->m_bVisible) continue;
  927. pButton->m_rcButton = CRect(CPoint(nLeft, m_rcGrid.bottom + 1), szButton);
  928. nLeft += nButtonLen;
  929. }
  930. }
  931. void CXTPDatePickerControl::CalcButtonBandRect()
  932. {
  933. SetButtonRect();
  934. }
  935. void CXTPDatePickerControl::DrawButtons(CDC* pDC)
  936. {
  937. for (int i = 0; i < GetButtonCount(); i++)
  938. {
  939. CXTPDatePickerButton* pButton = GetButton(i);
  940. if (pButton->m_bVisible)
  941. m_pPaintManager->DrawButton(pDC, pButton->m_rcButton, pButton->GetCaption(), pButton->m_bPressed, pButton->m_bHighlight);
  942. }
  943. }
  944. CXTPDatePickerItemMonth* CXTPDatePickerControl::HitTest(CPoint ptMouse)
  945. {
  946. // enumerate all month items in the collection
  947. int nMonthCount = (int)m_arrMonths.GetSize();
  948. for (int nIndex = 0; nIndex < nMonthCount; nIndex++)
  949. {
  950. CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nIndex);
  951. if (pMonth && pMonth->m_rcMonth.PtInRect(ptMouse))
  952. return pMonth;
  953. }
  954. return NULL;
  955. }
  956. void CXTPDatePickerControl::ScrollLeft(int nMonthCount)
  957. {
  958. int nYearNew = m_dtFirstMonth.GetYear() - nMonthCount / 12;
  959. int nMonthNew = m_dtFirstMonth.GetMonth() - nMonthCount % 12;
  960. if (nMonthNew < 1)
  961. {
  962. nMonthNew += 12;
  963. nYearNew--;
  964. }
  965. ASSERT(nMonthNew >= 1 && nMonthNew <= 12);
  966. if (m_dtMinRange.GetStatus() == COleDateTime::valid)
  967. {
  968. if (nYearNew < m_dtMinRange.GetYear())
  969. {
  970. nYearNew = m_dtMinRange.GetYear();
  971. nMonthNew = m_dtMinRange.GetMonth();
  972. }
  973. if (m_dtMinRange.GetYear() == nYearNew)
  974. {
  975. if (nMonthNew < m_dtMinRange.GetMonth())
  976. nMonthNew = m_dtMinRange.GetMonth();
  977. }
  978. }
  979. m_dtFirstMonth.SetDate(nYearNew, nMonthNew, 1);
  980. Populate();
  981. }
  982. void CXTPDatePickerControl::ScrollRight(int nMonthCount)
  983. {
  984. int nYearNew = m_dtFirstMonth.GetYear() + nMonthCount / 12;
  985. int nMonthNew = m_dtFirstMonth.GetMonth() + nMonthCount % 12;
  986. if (nMonthNew > 12)
  987. {
  988. nMonthNew -= 12;
  989. nYearNew++;
  990. }
  991. if (m_dtMaxRange.GetStatus() == COleDateTime::valid)
  992. {
  993. int nLeftMonth = m_dtMaxRange.GetMonth() - m_nRows * m_nColumns + 1;
  994. int nLeftYear = m_dtMaxRange.GetYear();
  995. if (nLeftMonth < 1)
  996. {
  997. nLeftYear -= (-nLeftMonth) / 12 + 1;
  998. nLeftMonth = -(((-nLeftMonth) % 12) - 12);
  999. }
  1000. if (nYearNew > nLeftYear)
  1001. {
  1002. nYearNew = nLeftYear;
  1003. nMonthNew = nLeftMonth;
  1004. }
  1005. if (nLeftYear == nYearNew)
  1006. {
  1007. if (nMonthNew > nLeftMonth)
  1008. nMonthNew = nLeftMonth;
  1009. }
  1010. }
  1011. m_dtFirstMonth.SetDate(nYearNew, nMonthNew, 1);
  1012. ScrollLeft(0); // adjust also scrolling left before calling Populate();
  1013. }
  1014. void CXTPDatePickerControl::OnTimeChange()
  1015. {
  1016. CWnd::OnTimeChange();
  1017. m_dtToday = CXTPCalendarUtils::GetCurrentTime();
  1018. _RedrawControl(FALSE);
  1019. }
  1020. void CXTPDatePickerControl::OnTimer(UINT_PTR nIDEvent)
  1021. {
  1022. if (nIDEvent == XTP_DATEPICKER_TIMERID)
  1023. {
  1024. if (m_mouseMode == mouseScrollingLeft)
  1025. ScrollLeft(GetMonthDelta());
  1026. else if (m_mouseMode == mouseScrollingRight)
  1027. ScrollRight(GetMonthDelta());
  1028. if ((m_mouseMode == mouseTrackingHeaderList) &&
  1029. (m_pListControl != NULL))
  1030. {
  1031. m_pListControl->OnTimer(nIDEvent);
  1032. }
  1033. }
  1034. CWnd::OnTimer(nIDEvent);
  1035. }
  1036. void CXTPDatePickerControl::ShowListHeader(CRect rcHeader, COleDateTime dtMonth)
  1037. {
  1038. // make sure that the list is not already created
  1039. ASSERT(!m_pListControl);
  1040. if (m_pListControl)
  1041. {
  1042. m_pListControl->DestroyWindow();
  1043. delete m_pListControl;
  1044. m_pListControl = NULL;
  1045. }
  1046. if (!m_bIsModal)
  1047. SetCapture();
  1048. // create list
  1049. m_pListControl = new CXTPDatePickerList(this, dtMonth);
  1050. if (!m_pListControl)
  1051. throw (new CMemoryException());
  1052. // create control
  1053. m_pListControl->Create(rcHeader);
  1054. m_nTimerID = (UINT)SetTimer(XTP_DATEPICKER_TIMERID, 2 * XTP_DATEPICKER_TIMER_INTERVAL / 3, NULL);
  1055. m_mouseMode = mouseTrackingHeaderList;
  1056. }
  1057. void CXTPDatePickerControl::Select(const COleDateTime& dtDay)
  1058. {
  1059. ClearFocus();
  1060. if (m_nMaxSelectionDays == XTP_SELECTION_INFINITE ||
  1061. m_nMaxSelectionDays > m_pSelectedDays->GetSelectedDaysCount())
  1062. {
  1063. m_pSelectedDays->Add(dtDay);
  1064. }
  1065. }
  1066. void CXTPDatePickerControl::Deselect(const COleDateTime& dtDay)
  1067. {
  1068. ClearFocus();
  1069. m_pSelectedDays->Remove(dtDay);
  1070. }
  1071. BOOL CXTPDatePickerControl::IsSelected(const COleDateTime& dtDay) const
  1072. {
  1073. BOOL bSelected = m_pSelectedDays->Contains(dtDay);
  1074. if (m_mouseMode == mouseSelecting ||
  1075. m_mouseMode == mouseDeselecting)
  1076. {
  1077. BOOL bBetween = FALSE;
  1078. if (m_dtFirstClicked <= m_dtLastClicked &&
  1079. m_dtFirstClicked <= dtDay && m_dtLastClicked >= dtDay)
  1080. {
  1081. bBetween = TRUE;
  1082. }
  1083. if (m_dtFirstClicked >= m_dtLastClicked &&
  1084. m_dtFirstClicked >= dtDay && m_dtLastClicked <= dtDay)
  1085. {
  1086. bBetween = TRUE;
  1087. }
  1088. if (bBetween && m_mouseMode == mouseSelecting)
  1089. {
  1090. COleDateTimeSpan spDays = dtDay - m_dtFirstClicked;
  1091. int nDays = abs(spDays.GetDays());
  1092. if (m_nMaxSelectionDays == XTP_SELECTION_INFINITE ||
  1093. m_pSelectedDays->GetSelectedDaysCount() + nDays < m_nMaxSelectionDays)
  1094. {
  1095. bSelected = TRUE;
  1096. }
  1097. }
  1098. if (bBetween && m_mouseMode == mouseDeselecting)
  1099. bSelected = FALSE;
  1100. }
  1101. return bSelected;
  1102. }
  1103. BOOL CXTPDatePickerControl::IsFocused(const COleDateTime& dtDay) const
  1104. {
  1105. if (m_dtFocused.GetStatus() != COleDateTime::valid)
  1106. {
  1107. return FALSE;
  1108. }
  1109. return CXTPCalendarUtils::IsEqual(CXTPCalendarUtils::ResetTime(m_dtFocused),
  1110.   CXTPCalendarUtils::ResetTime(dtDay));
  1111. }
  1112. void CXTPDatePickerControl::ClearFocus()
  1113. {
  1114. CXTPSelectionHelper _selector(this);
  1115. _selector.RemoveFocus();
  1116. }
  1117. void CXTPDatePickerControl::OnButtonClick(UINT nID)
  1118. {
  1119. XTP_NC_DATEPICKER_BUTTON nm;
  1120. nm.nID = nID;
  1121. SendNotification(XTP_NC_DATEPICKERBUTTONCLICKED, nID);
  1122. SendMessageToParent(XTP_NC_DATEPICKER_BUTTON_CLICK, (NMHDR*)&nm);
  1123. switch (nID)
  1124. {
  1125. case XTP_IDS_DATEPICKER_TODAY:
  1126. {
  1127. // behavior: change selection to today
  1128. ClearFocus();
  1129. m_pSelectedDays->Clear();
  1130. COleDateTime dt;
  1131. GetToday(dt);
  1132. EnsureVisible(dt);
  1133. Select(dt);
  1134. SendNotification(XTP_NC_DATEPICKERSELECTIONCHANGED);
  1135. SendMessageToParent(XTP_NC_DATEPICKER_SELECTION_CHANGED);
  1136. _EndModalIfNeed();
  1137. }
  1138. break;
  1139. case XTP_IDS_DATEPICKER_NONE:
  1140. {
  1141. // behavior: change selection
  1142. ClearFocus();
  1143. m_pSelectedDays->Clear();
  1144. SendNotification(XTP_NC_DATEPICKERSELECTIONCHANGED);
  1145. SendMessageToParent(XTP_NC_DATEPICKER_SELECTION_CHANGED);
  1146. _EndModalIfNeed();
  1147. }
  1148. break;
  1149. }
  1150. }
  1151. void CXTPDatePickerControl::ProcessButtons(CPoint point)
  1152. {
  1153. for (int i = 0; i < GetButtonCount(); i++)
  1154. {
  1155. CXTPDatePickerButton* pButton = GetButton(i);
  1156. BOOL bHighlight = pButton->m_rcButton.PtInRect(point);
  1157. if (pButton == m_pButtonCaptured)
  1158. {
  1159. if (bHighlight != pButton->m_bPressed)
  1160. {
  1161. pButton->m_bPressed = bHighlight;
  1162. _RedrawControl(FALSE);
  1163. }
  1164. }
  1165. else if (pButton->m_bPressed)
  1166. {
  1167. pButton->m_bPressed = FALSE;
  1168.  if (bHighlight)
  1169.  OnButtonClick(pButton->m_nID);
  1170. _RedrawControl(FALSE);
  1171. }
  1172. bHighlight = pButton->m_bHighlight;
  1173. pButton->m_bHighlight = ((m_pButtonCaptured == pButton) ||
  1174. (!m_pButtonCaptured && pButton->m_rcButton.PtInRect(point)));
  1175. if (pButton->m_bHighlight != bHighlight)
  1176. {
  1177. _RedrawControl(FALSE);
  1178. }
  1179. }
  1180. }
  1181. LRESULT CXTPDatePickerControl::SendMessageToParent(int nMessage, NMHDR* pNMHDR)
  1182. {
  1183. if (!IsWindow(m_hWnd))
  1184. return 0;
  1185. NMHDR nmhdr;
  1186. if (pNMHDR == NULL)
  1187. pNMHDR = &nmhdr;
  1188. pNMHDR->hwndFrom = GetSafeHwnd();
  1189. pNMHDR->idFrom = GetDlgCtrlID();
  1190. pNMHDR->code = nMessage;
  1191. CWnd *pOwner = GetOwner();
  1192. LRESULT res = 0;
  1193. if (pOwner && IsWindow(pOwner->m_hWnd))
  1194. res = pOwner->SendMessage(WM_NOTIFY, pNMHDR->idFrom, (LPARAM)pNMHDR);
  1195. return res;
  1196. }
  1197. void CXTPDatePickerControl::_EndModalIfNeed()
  1198. {
  1199. BOOL bSingleDaySel = (::GetKeyState(VK_CONTROL) & 0x8000) != 0 || IsMultiSelectionMode();
  1200. if (m_bIsModal && !bSingleDaySel)
  1201. {
  1202. if (ContinueModal()) // skip if EndModalLoop has already called
  1203. {
  1204. EndModalLoop(IDOK);
  1205. }
  1206. }
  1207. }
  1208. void CXTPDatePickerControl::SetButtonsVisible(BOOL bShowToday, BOOL bShowNone)
  1209. {
  1210. m_arrButtons.Find(XTP_IDS_DATEPICKER_TODAY)->m_bVisible = bShowToday;
  1211. m_arrButtons.Find(XTP_IDS_DATEPICKER_NONE)->m_bVisible = bShowNone;
  1212. if (!m_rcControl.IsRectEmpty())
  1213. {
  1214. AdjustLayout(m_rcControl);
  1215. _RedrawControl(FALSE);
  1216. }
  1217. }
  1218. void CXTPDatePickerControl::EnsureVisible(const COleDateTime& dtDate)
  1219. {
  1220. int nYear = dtDate.GetYear();
  1221. int nMonth = dtDate.GetMonth();
  1222. // enumerate all month items in the collection
  1223. int nMonthCount = (int)m_arrMonths.GetSize();
  1224. for (int nIndex = 0; nIndex < nMonthCount; nIndex++)
  1225. {
  1226. CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nIndex);
  1227. if (pMonth)
  1228. {
  1229. if (pMonth->GetMonth().GetMonth() == nMonth && pMonth->GetMonth().GetYear() == nYear)
  1230. return;
  1231. }
  1232. }
  1233. m_dtFirstMonth.SetDate(nYear, nMonth, 1);
  1234. Populate();
  1235. }
  1236. AFX_INLINE int GetEqualLeftSymbols(const CString& str1, const CString& str2)
  1237. {
  1238. int nCount = min(str1.GetLength(), str2.GetLength());
  1239. for (int i = 0; i < nCount; i++)
  1240. {
  1241. if (str1.GetAt(i) != str2.GetAt(i))
  1242. return i;
  1243. }
  1244. return nCount;
  1245. }
  1246. void CXTPDatePickerControl::InitNames()
  1247. {
  1248. // initialize month names
  1249. for (int nMonth = 0; nMonth < 12; nMonth++)
  1250. {
  1251. CString strMonth = CXTPCalendarUtils::GetLocaleString(LOCALE_SMONTHNAME1 + nMonth, 255) ;
  1252. m_arMonthNames[nMonth] = strMonth;
  1253. }
  1254. int nEqualLeftSymbols = 255, nDay;
  1255. // initialize day names
  1256. for (nDay = 0; nDay < 7; nDay++)
  1257. {
  1258. CString strDayName = CXTPCalendarUtils::GetLocaleString(LOCALE_SABBREVDAYNAME1 + nDay, 255);
  1259. int nOleDayOfWeek = (nDay + 1) % 7;
  1260. m_arDayOfWeekNames[nOleDayOfWeek] = strDayName;
  1261. if (nDay > 0 && nEqualLeftSymbols > 0)
  1262. {
  1263. nEqualLeftSymbols = min(nEqualLeftSymbols, GetEqualLeftSymbols(strDayName, m_arDayOfWeekNames[1]));
  1264. }
  1265. }
  1266. // If first symbols equal, remove them.
  1267. if (nEqualLeftSymbols > 0)
  1268. {
  1269. for (nDay = 0; nDay < 7; nDay++)
  1270. {
  1271. DELETE_S(m_arDayOfWeekNames[nDay], 0, nEqualLeftSymbols);
  1272. }
  1273. }
  1274. }
  1275. void CXTPDatePickerControl::SetShowNonMonthDays(BOOL bShow)
  1276. {
  1277. if (bShow != m_bShowNonMonthDays)
  1278. {
  1279. m_bShowNonMonthDays = bShow;
  1280. // set first month and last month defaults
  1281. int nMonthCount = (int)m_arrMonths.GetSize();
  1282. if (nMonthCount > 0)
  1283. {
  1284. CXTPDatePickerItemMonth* pFirstMonth = m_arrMonths.GetAt(0);
  1285. CXTPDatePickerItemMonth* pLastMonth = m_arrMonths.GetAt(nMonthCount - 1);
  1286. // by default set show previous days for first month and show following days for last month
  1287. pFirstMonth->SetShowDaysBefore(bShow);
  1288. pLastMonth->SetShowDaysAfter(bShow);
  1289. }
  1290. _RedrawControl(FALSE);
  1291. }
  1292. }
  1293. void CXTPDatePickerControl::AllowNoncontinuousSelection(BOOL bAllow /*= TRUE*/)
  1294. {
  1295. m_bAllowNoncontinuousSelection = bAllow;
  1296. if (!m_bAllowNoncontinuousSelection && m_pSelectedDays->GetSelectedBlocksCount() > 1)
  1297. {
  1298. m_pSelectedDays->Clear();
  1299. _RedrawControl(FALSE);
  1300. }
  1301. }
  1302. void CXTPDatePickerControl::SetMaxSelCount(int nMax)
  1303. {
  1304. m_nMaxSelectionDays = nMax;
  1305. int nCurrentSelectedDays = m_pSelectedDays->GetSelectedDaysCount();
  1306. // clear extra days
  1307. if (nCurrentSelectedDays > m_nMaxSelectionDays)
  1308. {
  1309. m_pSelectedDays->Clear();
  1310. _RedrawControl(FALSE);
  1311. }
  1312. }
  1313. BOOL CXTPDatePickerControl::GetSelRange(COleDateTime& refMinRange, COleDateTime& refMaxRange) const
  1314. {
  1315. return m_pSelectedDays->GetMinMaxRange(refMinRange, refMaxRange);
  1316. }
  1317. BOOL CXTPDatePickerControl::SetSelRange(const COleDateTime& dtMinRange, const COleDateTime& dtMaxRange)
  1318. {
  1319. ClearFocus();
  1320. m_pSelectedDays->SelectRange(dtMinRange, dtMaxRange);
  1321. m_dtFirstClicked = dtMinRange;
  1322. m_dtLastClicked = dtMaxRange;
  1323. return TRUE;
  1324. }
  1325. BOOL CXTPDatePickerControl::SizeMinReq(BOOL bRepaint /* = TRUE */)
  1326. {
  1327. CRect rect;
  1328. BOOL bRetVal = FALSE;
  1329. if (GetMinReqRect(rect))
  1330. {
  1331. DWORD dwFlags = SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOMOVE | SWP_NOACTIVATE;
  1332. if (!bRepaint)
  1333. dwFlags |= SWP_NOREDRAW;
  1334. SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), dwFlags);
  1335. bRetVal = TRUE;
  1336. }
  1337. return bRetVal;
  1338. }
  1339. BOOL CXTPDatePickerControl::GetMinReqRect(RECT* pRect) const
  1340. {
  1341. return GetMinReqRect(pRect, 1, 1);
  1342. }
  1343. BOOL CXTPDatePickerControl::GetMinReqRect(RECT* pRect, int nRows, int nCols) const
  1344. {
  1345. CWindowDC dc(GetDesktopWindow());
  1346. CSize szMonth(m_pPaintManager->CalcMonthRect(&dc));
  1347. pRect->left = pRect->top = 0;
  1348. pRect->right = szMonth.cx * nCols;
  1349. pRect->bottom = szMonth.cy * nRows;
  1350. CRect rcBorder(0, 0, 0, 0);
  1351. m_pPaintManager->DrawBorder(0, this, rcBorder, FALSE);
  1352. pRect->right += rcBorder.left - rcBorder.right;
  1353. pRect->bottom += rcBorder.top - rcBorder.bottom;
  1354. if (m_arrButtons.GetVisibleButtonCount() > 0)
  1355. {
  1356. CSize szButton(CalcButtonSize());
  1357. pRect->bottom += szButton.cy;
  1358. }
  1359. return TRUE;
  1360. }
  1361. BOOL CXTPDatePickerControl::GetCurSel(COleDateTime& refDateTime) const
  1362. {
  1363. return m_pSelectedDays->GetMinMaxRange(refDateTime, refDateTime);
  1364. }
  1365. BOOL CXTPDatePickerControl::SetCurSel(const COleDateTime& refDateTime)
  1366. {
  1367. return SetSelRange(refDateTime, refDateTime);
  1368. }
  1369. void CXTPDatePickerControl::SetToday(const COleDateTime& refDateTime)
  1370. {
  1371. m_dtToday = refDateTime;
  1372. _RedrawControl(FALSE);
  1373. }
  1374. DWORD CXTPDatePickerControl::GetRange(COleDateTime* pMinRange, COleDateTime* pMaxRange) const
  1375. {
  1376. DWORD dwRes = 0;
  1377. if (pMinRange && m_dtMinRange.GetStatus() == COleDateTime::valid)
  1378. {
  1379. *pMinRange = m_dtMinRange;
  1380. dwRes |= GDTR_MIN;
  1381. }
  1382. if (pMaxRange && m_dtMaxRange.GetStatus() == COleDateTime::valid)
  1383. {
  1384. *pMaxRange = m_dtMaxRange;
  1385. dwRes |= GDTR_MAX;
  1386. }
  1387. return dwRes;
  1388. }
  1389. BOOL CXTPDatePickerControl::SetRange(const COleDateTime* pMinRange, const COleDateTime* pMaxRange)
  1390. {
  1391. if (pMinRange)
  1392. {
  1393. m_dtMinRange = *pMinRange;
  1394. ScrollLeft(0);
  1395. }
  1396. if (pMaxRange)
  1397. {
  1398. m_dtMaxRange = *pMaxRange;
  1399. ScrollRight(0);
  1400. }
  1401. return TRUE;
  1402. }
  1403. int CXTPDatePickerControl::GetMonthRange(COleDateTime& refMinRange, COleDateTime& refMaxRange, DWORD dwFlags) const
  1404. {
  1405. refMinRange = m_dtFirstMonth;
  1406. refMaxRange = m_dtFirstMonth;
  1407. int nMonthCount = m_nRows * m_nColumns;
  1408. ShiftDate(refMaxRange, nMonthCount);
  1409. //if (GMR_DAYSTATE == dwFlags)
  1410. // do nothing
  1411. if (GMR_VISIBLE == dwFlags)
  1412. {
  1413. nMonthCount = (int)m_arrMonths.GetSize();
  1414. if (nMonthCount > 0)
  1415. {
  1416. CXTPDatePickerItemMonth* pLastMonth = m_arrMonths.GetAt(nMonthCount - 1);
  1417. if (pLastMonth)
  1418. {
  1419. CXTPDatePickerItemDay* pLastDay = pLastMonth->m_arrDays.GetAt(XTP_MAX_WEEKS * XTP_WEEK_DAYS - 1);
  1420. if (pLastDay->GetDate().GetMonth() != refMaxRange.GetMonth())
  1421. {
  1422. ShiftDate(refMaxRange, 1);
  1423. nMonthCount++;
  1424. }
  1425. }
  1426. CXTPDatePickerItemMonth* pFirstMonth = m_arrMonths.GetAt(0);
  1427. if (pFirstMonth)
  1428. {
  1429. CXTPDatePickerItemDay* pFirstDay = pFirstMonth->m_arrDays.GetAt(0);
  1430. if (pFirstDay->GetDate().GetMonth() != refMinRange.GetMonth())
  1431. {
  1432. ShiftDate(refMinRange, -1);
  1433. nMonthCount++;
  1434. }
  1435. }
  1436. }
  1437. }
  1438. return nMonthCount;
  1439. }
  1440. BOOL CXTPDatePickerControl::ShiftDate(COleDateTime &refDate, int nMonthCount)
  1441. {
  1442. int nYearNew = refDate.GetYear();
  1443. int nMonthNew = refDate.GetMonth();
  1444. int nInc = abs(nMonthCount) / nMonthCount;
  1445. for (int nItem = 0; nItem < abs(nMonthCount); nItem++)
  1446. {
  1447. nMonthNew += nInc;
  1448. if (nMonthNew < 1)
  1449. {
  1450. nMonthNew = 12;
  1451. nYearNew--;
  1452. }
  1453. if (nMonthNew > 12)
  1454. {
  1455. nMonthNew = 1;
  1456. nYearNew++;
  1457. }
  1458. }
  1459. return 0 == refDate.SetDate(nYearNew, nMonthNew, 1);
  1460. }
  1461. void XTPGetAsSystemTime(const COleDateTime& dateTime, SYSTEMTIME& st)
  1462. {
  1463. #if _MSC_VER < 1200
  1464. UNREFERENCED_PARAMETER(dateTime);
  1465. UNREFERENCED_PARAMETER(st);
  1466. ASSERT(FALSE);
  1467. #else
  1468. dateTime.GetAsSystemTime(st);
  1469. #endif
  1470. }
  1471. DWORD CXTPDatePickerControl::HitTest(PMCHITTESTINFO pMCHitTest)
  1472. {
  1473. // check structure
  1474. if (!pMCHitTest)
  1475. return 0;
  1476. ASSERT(sizeof(MCHITTESTINFO) == pMCHitTest->cbSize);
  1477. // default result
  1478. pMCHitTest->uHit = MCHT_NOWHERE;
  1479. // start checking
  1480. CPoint ptHit(pMCHitTest->pt);
  1481. CXTPDatePickerItemMonth* pHitMonth = HitTest(ptHit);
  1482. if (pHitMonth)
  1483. {
  1484. CXTPDatePickerItemDay* pHitDay = pHitMonth->HitTest(ptHit);
  1485. if (pHitDay)
  1486. {
  1487. // MCHT_CALENDARDATE
  1488. pMCHitTest->uHit = MCHT_CALENDARDATE;
  1489. XTPGetAsSystemTime(pHitDay->GetDate(), pMCHitTest->st);
  1490. // MCHT_CALENDARDATEPREV
  1491. if (pHitMonth->GetShowDaysBefore() &&
  1492. pHitMonth->GetMonth().GetMonth() < pHitDay->GetDate().GetMonth())
  1493. {
  1494. pMCHitTest->uHit = MCHT_CALENDARDATEPREV;
  1495. }
  1496. else
  1497. // MCHT_CALENDARDATENEXT
  1498. if (pHitMonth->GetShowDaysAfter() &&
  1499. pHitMonth->GetMonth().GetMonth() > pHitDay->GetDate().GetMonth())
  1500. {
  1501. pMCHitTest->uHit = MCHT_CALENDARDATENEXT;
  1502. }
  1503. }
  1504. else
  1505. {
  1506. XTPGetAsSystemTime(pHitMonth->GetMonth(), pMCHitTest->st);
  1507. // MCHT_CALENDARDAY
  1508. if (pHitMonth->m_rcDaysOfWeek.PtInRect(ptHit))
  1509. {
  1510. pMCHitTest->uHit = MCHT_CALENDARDAY;
  1511. // The SYSTEMTIME structure at lpMCHitTest>st is set to the corresponding date in the top row.
  1512. CPoint ptTopRow(ptHit.x, pHitMonth->m_rcDaysOfWeek.bottom + 1);
  1513. CXTPDatePickerItemDay* pDay = pHitMonth->HitTest(ptTopRow);
  1514. if (pDay)
  1515. {
  1516. XTPGetAsSystemTime(pDay->GetDate(), pMCHitTest->st);
  1517. }
  1518. }
  1519. else
  1520. // MCHT_CALENDARWEEKNUM
  1521. if (pHitMonth->m_rcWeekNumbers.PtInRect(ptHit))
  1522. {
  1523. pMCHitTest->uHit = MCHT_CALENDARWEEKNUM;
  1524. // The SYSTEMTIME structure at lpMCHitTest>st is set to the corresponding date in the leftmost column
  1525. CPoint ptLeftRow(pHitMonth->m_rcWeekNumbers.right + 1, ptHit.y);
  1526. CXTPDatePickerItemDay* pDay = pHitMonth->HitTest(ptLeftRow);
  1527. if (pDay)
  1528. {
  1529. XTPGetAsSystemTime(pDay->GetDate(), pMCHitTest->st);
  1530. }
  1531. }
  1532. else
  1533. // MCHT_TITLEMONTH
  1534. if (pHitMonth->m_rcHeader.PtInRect(ptHit))
  1535. {
  1536. pMCHitTest->uHit = MCHT_TITLEMONTH;
  1537. }
  1538. else
  1539. // MCHT_TITLEBTNNEXT
  1540. if (pHitMonth->GetShowRightScroll() &&
  1541. pHitMonth->m_rcRightScroll.PtInRect(ptHit))
  1542. {
  1543. pMCHitTest->uHit = MCHT_TITLEBTNNEXT;
  1544. }
  1545. else
  1546. // MCHT_TITLEBTNPREV
  1547. if (pHitMonth->GetShowLeftScroll() &&
  1548. pHitMonth->m_rcLeftScroll.PtInRect(ptHit))
  1549. {
  1550. pMCHitTest->uHit = MCHT_TITLEBTNPREV;
  1551. }
  1552. }
  1553. }
  1554. else
  1555. {
  1556. // MCHT_CALENDARBK
  1557. pMCHitTest->uHit = MCHT_CALENDARBK;
  1558. }
  1559. return pMCHitTest->uHit;
  1560. }
  1561. void CXTPDatePickerControl::SetBorderStyle(XTPDatePickerBorderStyle borderStyle)
  1562. {
  1563. m_borderStyle = borderStyle;
  1564. AdjustLayout(m_rcControl);
  1565. _RedrawControl(FALSE);
  1566. }
  1567. void CXTPDatePickerControl::SetAutoSize(BOOL bAuto)
  1568. {
  1569. m_bAutoSize = bAuto;
  1570. AdjustLayout(m_rcControl);
  1571. _RedrawControl(FALSE);
  1572. }
  1573. void CXTPDatePickerControl::OnSysColorChange()
  1574. {
  1575. m_pPaintManager->RefreshMetrics();
  1576. AdjustLayout(m_rcControl);
  1577. _RedrawControl(FALSE);
  1578. }
  1579. BOOL CXTPDatePickerControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  1580. {
  1581. if (nHitTest == HTCLIENT)
  1582. {
  1583. CPoint point;
  1584. ::GetCursorPos(&point);
  1585. ScreenToClient(&point);
  1586. CXTPDatePickerItemMonth* pMonth = HitTest(point);
  1587. if (pMonth)
  1588. {
  1589. BOOL bRet = pMonth->OnSetCursor(point);
  1590. if (bRet)
  1591. return bRet;
  1592. }
  1593. }
  1594. return CWnd::OnSetCursor(pWnd, nHitTest, message);
  1595. }
  1596. void CXTPDatePickerControl::OnSetFocus(CWnd* pOldWnd)
  1597. {
  1598. CWnd::OnSetFocus(pOldWnd);
  1599. RedrawControl();
  1600. #ifdef XTP_DATEPICKER_SITENOTIFY_ONFOCUS
  1601. XTP_DATEPICKER_SITENOTIFY_ONFOCUS(this, this, TRUE)
  1602. #endif
  1603. }
  1604. void CXTPDatePickerControl::OnKillFocus (CWnd* pNewWnd)
  1605. {
  1606. CWnd::OnKillFocus(pNewWnd);
  1607. RedrawControl();
  1608. #ifdef XTP_DATEPICKER_SITENOTIFY_ONFOCUS
  1609. XTP_DATEPICKER_SITENOTIFY_ONFOCUS(this, this, FALSE)
  1610. #endif
  1611. }
  1612. void CXTPDatePickerControl::OnFinalRelease()
  1613. {
  1614. CWnd::OnFinalRelease();
  1615. if (m_bDeleteOnFinalRelease)
  1616. {
  1617. CCmdTarget::OnFinalRelease();
  1618. }
  1619. }
  1620. void CXTPDatePickerControl::OnEnable(BOOL bEnable)
  1621. {
  1622. UNREFERENCED_PARAMETER(bEnable);
  1623. _RedrawControl(FALSE);
  1624. }
  1625. BOOL CXTPDatePickerControl::GetVisibleRange(COleDateTime& refFirstVisibleDay,
  1626. COleDateTime& refLastVisibleDay) const
  1627. {
  1628. int nCount = (int)m_arrMonths.GetSize();
  1629. if (!nCount || !m_arrMonths[0] || !m_arrMonths[nCount-1])
  1630. {
  1631. return FALSE;
  1632. }
  1633. if (!m_arrMonths[0]->GetDay(0))
  1634. {
  1635. ASSERT(FALSE);
  1636. return FALSE;
  1637. }
  1638. refFirstVisibleDay = m_arrMonths[0]->GetDay(0)->GetDate();
  1639. if (!m_arrMonths[0]->GetShowDaysBefore())
  1640. {
  1641. int nFirstMnDCount = m_arrMonths[0]->GetDayCount();
  1642. for (int i = 1; i < nFirstMnDCount; i++)
  1643. {
  1644. if (refFirstVisibleDay.GetMonth() == m_arrMonths[0]->GetMonth().GetMonth())
  1645. {
  1646. break;
  1647. }
  1648. refFirstVisibleDay = m_arrMonths[0]->GetDay(i)->GetDate();
  1649. }
  1650. ASSERT(refFirstVisibleDay.GetMonth() == m_arrMonths[0]->GetMonth().GetMonth());
  1651. }
  1652. int nLastMnDCount = m_arrMonths[nCount-1]->GetDayCount();
  1653. if (!nLastMnDCount || !m_arrMonths[nCount-1]->GetDay(nLastMnDCount-1))
  1654. {
  1655. ASSERT(FALSE);
  1656. return FALSE;
  1657. }
  1658. refLastVisibleDay = m_arrMonths[nCount-1]->GetDay(nLastMnDCount-1)->GetDate();
  1659. if (!m_arrMonths[nCount-1]->GetShowDaysAfter())
  1660. {
  1661. for (int i = nLastMnDCount-2; i > 0 ; i--)
  1662. {
  1663. if (refLastVisibleDay.GetMonth() == m_arrMonths[nCount-1]->GetMonth().GetMonth())
  1664. {
  1665. break;
  1666. }
  1667. refLastVisibleDay = m_arrMonths[nCount-1]->GetDay(i)->GetDate();
  1668. }
  1669. ASSERT(refLastVisibleDay.GetMonth() == m_arrMonths[nCount-1]->GetMonth().GetMonth());
  1670. }
  1671. return TRUE;
  1672. }
  1673. void CXTPDatePickerControl::EnsureVisibleSelection()
  1674. {
  1675. COleDateTime dtFirstSelDay, dtLastSelDay;
  1676. COleDateTime dtFirstVisibleDay, dtLastVisibleDay;
  1677. BOOL bRes1 = GetVisibleRange(dtFirstVisibleDay, dtLastVisibleDay);
  1678. BOOL bRes2 = GetSelRange(dtFirstSelDay, dtLastSelDay);
  1679. if (bRes1 && bRes2)
  1680. {
  1681. if (dtFirstSelDay > dtLastVisibleDay)
  1682. {
  1683. int nMonths = CXTPCalendarUtils::GetDiff_Months(dtFirstSelDay, dtLastVisibleDay);
  1684. nMonths += CXTPCalendarUtils::GetDiff_Months(dtLastSelDay, dtFirstSelDay);
  1685. nMonths = max(nMonths, 1);
  1686. ScrollRight(nMonths);
  1687. }
  1688. else if (dtLastSelDay > dtLastVisibleDay)
  1689. {
  1690. int nMonths = CXTPCalendarUtils::GetDiff_Months(dtLastSelDay, dtLastVisibleDay);
  1691. nMonths = max(nMonths, 1);
  1692. ScrollRight(nMonths);
  1693. }
  1694. //---------------------------
  1695. bRes1 = GetVisibleRange(dtFirstVisibleDay, dtLastVisibleDay);
  1696. bRes2 = GetSelRange(dtFirstSelDay, dtLastSelDay);
  1697. if (bRes1 && bRes2)
  1698. {
  1699. if (dtFirstSelDay < dtFirstVisibleDay || dtLastSelDay > dtLastVisibleDay)
  1700. {
  1701. EnsureVisible(dtLastSelDay);
  1702. EnsureVisible(dtFirstSelDay);
  1703. }
  1704. }
  1705. }
  1706. }
  1707. void CXTPDatePickerControl::SetLayoutRTL(BOOL bRightToLeft)
  1708. {
  1709. if (!XTPSystemVersion()->IsLayoutRTLSupported())
  1710. return;
  1711. m_bRightToLeft = bRightToLeft;
  1712. if (!m_hWnd)
  1713. return;
  1714. ModifyStyleEx(bRightToLeft ? 0 : WS_EX_LAYOUTRTL, !bRightToLeft ? 0 : WS_EX_LAYOUTRTL);
  1715. RedrawControl();
  1716. }
  1717. void CXTPDatePickerControl::EnsureVisibleFocus()
  1718. {
  1719. if (m_dtFocused.GetStatus() != COleDateTime::valid)
  1720. {
  1721. return;
  1722. }
  1723. COleDateTime dtFirstVisibleDay, dtLastVisibleDay;
  1724. BOOL bRes1 = GetVisibleRange(dtFirstVisibleDay, dtLastVisibleDay);
  1725. if (bRes1)
  1726. {
  1727. if (m_dtFocused > dtLastVisibleDay)
  1728. {
  1729. int nMonths = CXTPCalendarUtils::GetDiff_Months(m_dtFocused, dtLastVisibleDay);
  1730. nMonths = max(nMonths, 1);
  1731. ScrollRight(nMonths);
  1732. }
  1733. //---------------------------
  1734. bRes1 = GetVisibleRange(dtFirstVisibleDay, dtLastVisibleDay);
  1735. if (bRes1)
  1736. {
  1737. if (m_dtFocused < dtFirstVisibleDay || m_dtFocused > dtLastVisibleDay)
  1738. {
  1739. EnsureVisible(m_dtFocused);
  1740. }
  1741. }
  1742. }
  1743. }
  1744. XTPCalendarTheme CXTPDatePickerControl::GetPaintTheme() const
  1745. {
  1746. if (m_pPaintManager)
  1747. return m_pPaintManager->GetPaintTheme();
  1748. return xtpCalendarThemeUnknown;
  1749. }
  1750. void CXTPDatePickerControl::SetPaintTheme(XTPCalendarTheme ePaintTheme)
  1751. {
  1752. if (ePaintTheme == xtpCalendarThemeOffice2007)
  1753. {
  1754. SetTheme(new CXTPDatePickerThemeOffice2007());
  1755. }
  1756. else
  1757. {
  1758. SetTheme(NULL);
  1759. if (m_pPaintManager)
  1760. m_pPaintManager->SetPaintTheme(ePaintTheme);
  1761. }
  1762. }
  1763. /////////////////////////////////////////////////////////////////////////////
  1764. //class CXTPSelectionHelper
  1765. CXTPDatePickerControl::CXTPSelectionHelper::CXTPSelectionHelper(CXTPDatePickerControl* pControl)
  1766. {
  1767. ASSERT(pControl);
  1768. m_pDP = pControl;
  1769. }
  1770. void CXTPDatePickerControl::CXTPSelectionHelper::InitFocusIfNeed()
  1771. {
  1772. if (m_pDP->m_dtFocused.GetStatus() != COleDateTime::valid)
  1773. {
  1774. COleDateTime dtSel0, dtSel1;
  1775. BOOL bSelExists = m_pDP->GetSelectedDays()->GetMinMaxRange(dtSel0, dtSel1);
  1776. if (!bSelExists)
  1777. {
  1778. dtSel0.SetDate(m_pDP->m_dtFirstMonth.GetYear(), m_pDP->m_dtFirstMonth.GetMonth(), 1);
  1779. }
  1780. m_pDP->m_dtFocused = dtSel0;
  1781. if (m_pDP->m_dtFirstClicked.GetStatus() == COleDateTime::valid &&
  1782. m_pDP->m_dtFirstClicked >= dtSel0 && m_pDP->m_dtFirstClicked <= dtSel1)
  1783. {
  1784. m_pDP->m_dtFSelBase = m_pDP->m_dtFirstClicked;
  1785. }
  1786. else
  1787. {
  1788. m_pDP->m_dtFSelBase = dtSel0;
  1789. }
  1790. }
  1791. }
  1792. void CXTPDatePickerControl::CXTPSelectionHelper::RemoveFocus()
  1793. {
  1794. m_pDP->m_dtFocused.SetStatus(COleDateTime::null);
  1795. m_pDP->m_dtFSelBase.SetStatus(COleDateTime::null);
  1796. }
  1797. void CXTPDatePickerControl::CXTPSelectionHelper::_TmpSaveFocus()
  1798. {
  1799. m_dtFocusedTmp = m_pDP->m_dtFocused;
  1800. m_dtFSelBaseTmp = m_pDP->m_dtFSelBase;
  1801. }
  1802. void CXTPDatePickerControl::CXTPSelectionHelper::_TmpRestoreFocus()
  1803. {
  1804. m_pDP->m_dtFocused = m_dtFocusedTmp;
  1805. m_pDP->m_dtFSelBase = m_dtFSelBaseTmp;
  1806. }
  1807. void CXTPDatePickerControl::CXTPSelectionHelper::MoveFocus(int eStep, int eDirection,
  1808. BOOL bContinuouse, BOOL bSaveSel)
  1809. {
  1810. ASSERT(eDirection == 1 || eDirection == -1);
  1811. if (bContinuouse)
  1812. {
  1813. bSaveSel = FALSE;
  1814. }
  1815. InitFocusIfNeed();
  1816. _MoveFocus(eStep, eDirection);
  1817. if (bContinuouse)
  1818. {
  1819. COleDateTime dtSel0 = m_pDP->m_dtFocused;
  1820. COleDateTime dtSel1 = m_pDP->m_dtFSelBase;
  1821. BOOL bBackSel = dtSel0 > dtSel1;
  1822. if (bBackSel)
  1823. {
  1824. dtSel1 = m_pDP->m_dtFocused;
  1825. dtSel0 = m_pDP->m_dtFSelBase;
  1826. }
  1827. int nDays = (int)dtSel1 - (int)dtSel0;
  1828. int nMaxSel = m_pDP->GetMaxSelCount();
  1829. if (nMaxSel == XTP_SELECTION_INFINITE)
  1830. {
  1831. nMaxSel = INT_MAX;
  1832. }
  1833. if (nDays > nMaxSel)
  1834. {
  1835. if (bBackSel)
  1836. {
  1837. dtSel1 = (double)dtSel0 + nMaxSel;
  1838. }
  1839. else
  1840. {
  1841. dtSel0 = (double)dtSel1 - nMaxSel;
  1842. }
  1843. }
  1844. m_pDP->GetSelectedDays()->Clear();
  1845. m_pDP->GetSelectedDays()->SelectRange(dtSel0, dtSel1);
  1846. }
  1847. else
  1848. {
  1849. //int nSelDays = m_pDP->GetSelectedDays()->GetSelectedDaysCount();
  1850. if (!bSaveSel)
  1851. {
  1852. m_pDP->GetSelectedDays()->Clear();
  1853. }
  1854. if (!bSaveSel /*|| nSelDays == 0*/)
  1855. {
  1856. m_pDP->GetSelectedDays()->Add(m_pDP->m_dtFocused);
  1857. }
  1858. m_pDP->m_dtFSelBase = m_pDP->m_dtFocused;
  1859. }
  1860. }
  1861. void CXTPDatePickerControl::CXTPSelectionHelper::SelUnselFocus()
  1862. {
  1863. InitFocusIfNeed();
  1864. BOOL bSelected = m_pDP->GetSelectedDays()->Contains(m_pDP->m_dtFocused);
  1865. if (bSelected)
  1866. {
  1867. m_pDP->GetSelectedDays()->Remove(m_pDP->m_dtFocused);
  1868. }
  1869. else
  1870. {
  1871. int nSelDays = m_pDP->GetSelectedDays()->GetSelectedDaysCount();
  1872. int nMaxSel = m_pDP->GetMaxSelCount();
  1873. if (nMaxSel == XTP_SELECTION_INFINITE)
  1874. {
  1875. nMaxSel = INT_MAX;
  1876. }
  1877. if (nSelDays < nMaxSel)
  1878. {
  1879. m_pDP->GetSelectedDays()->Add(m_pDP->m_dtFocused);
  1880. }
  1881. }
  1882. }
  1883. void CXTPDatePickerControl::CXTPSelectionHelper::_MoveFocus(int eStep, int eDirection)
  1884. {
  1885. ASSERT(eDirection == 1 || eDirection == -1);
  1886. InitFocusIfNeed();
  1887. COleDateTime dtNew = m_pDP->m_dtFocused;
  1888. if (eStep == stepDay || eStep == stepWeek)
  1889. {
  1890. dtNew = (double)dtNew + eDirection * (eStep == stepDay ? 1 : 7);
  1891. }
  1892. else if (eStep == stepMonth || eStep == stepYear)
  1893. {
  1894. int nMonths = eDirection * (eStep == stepMonth ? 1 : 12);
  1895. CXTPCalendarUtils::ShiftDate_Month(dtNew, nMonths, dtNew.GetDay());
  1896. }
  1897. else if (eStep == stepWeekBE)
  1898. {
  1899. int nFWD = m_pDP->GetFirstDayOfWeek();
  1900. int nShift = -1 * ((dtNew.GetDayOfWeek() - nFWD + 7) % 7);
  1901. if (eDirection == dirNext)
  1902. {
  1903. nShift += 6;
  1904. }
  1905. dtNew = (double)dtNew + nShift;
  1906. }
  1907. else if (eStep == stepMonthBE)
  1908. {
  1909. CXTPCalendarUtils::UpdateMonthDay(dtNew, eDirection == dirPrev ? 1 : 31);
  1910. }
  1911. else
  1912. {
  1913. ASSERT(FALSE);
  1914. }
  1915. m_pDP->m_dtFocused = dtNew;
  1916. }