// XTPDatePickerItemMonth.cpp: implementation of the CXTPDatePickerItemMonth class. // // This file is a part of the XTREME CALENDAR MFC class library. // (c)1998-2012 Codejock Software, All Rights Reserved. // // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN // CONSENT OF CODEJOCK SOFTWARE. // // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A // SINGLE COMPUTER. // // CONTACT INFORMATION: // support@codejock.com // http://www.codejock.com // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Common/XTPColorManager.h" #include "XTPCalendarDefines.h" #include "XTPDatePickerItemMonth.h" #include "XTPDatePickerControl.h" #include "XTPDatePickerPaintManager.h" #include "XTPDatePickerItemDay.h" #include "XTPDatePickerDaysCollection.h" #include "XTPCalendarUtils.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CXTPDatePickerItemMonth CXTPDatePickerItemMonth::CXTPDatePickerItemMonth(CXTPDatePickerControl* pControl, COleDateTime dtMonth, int nRow, int nCol) : m_nRow(nRow), m_nColumn(nCol), m_pControl(pControl), m_dtMonth(dtMonth) { m_rcHeader.SetRectEmpty(); m_rcDaysOfWeek.SetRectEmpty(); m_rcWeekNumbers.SetRectEmpty(); m_rcDaysArea.SetRectEmpty(); m_rcLeftScroll.SetRectEmpty(); m_rcRightScroll.SetRectEmpty(); m_bShowDaysBefore = FALSE; m_bShowDaysAfter = FALSE; m_bShowLeftScroll = FALSE; m_bShowRightScroll = FALSE; PopulateDays(); } CXTPDatePickerItemMonth::~CXTPDatePickerItemMonth() { ClearDays(); } void CXTPDatePickerItemMonth::PopulateDays() { if (m_dtMonth.GetYear() <= 100 && m_dtMonth.GetMonth() <= 2) m_dtMonth = COleDateTime(100,2,1,0,0,0); if (m_dtMonth.GetStatus() != COleDateTime::valid) { ASSERT(FALSE); m_dtMonth = CXTPCalendarUtils::ResetTime(COleDateTime::GetCurrentTime()); } //if (m_dtMonth < COleDateTime(1601,4,1,0,0,0)) // m_dtMonth = COleDateTime(1601,4,1,0,0,0); // init days from 1st to last COleDateTime dtDay(m_dtMonth.GetYear(), m_dtMonth.GetMonth(), 1, 0, 0, 0); COleDateTimeSpan spDay(1, 0, 0, 0); // adjust first day of the week int nOleFirstDayOfWeek = m_pControl->GetFirstDayOfWeek(); int iDayOfWeek = dtDay.GetDayOfWeek(); if (iDayOfWeek != -1) { while (dtDay.GetDayOfWeek() != nOleFirstDayOfWeek && dtDay.GetDayOfWeek() != -1) { dtDay -= spDay; } } else { COleDateTime dtFutureDay(dtDay); dtFutureDay.SetDate(dtFutureDay.GetYear() + 2000, dtFutureDay.GetMonth(), dtFutureDay.GetDay()); iDayOfWeek = dtFutureDay.GetDayOfWeek(); while (dtFutureDay.GetDayOfWeek() != nOleFirstDayOfWeek && dtFutureDay.GetDayOfWeek() != -1) { dtFutureDay -= spDay; dtDay -= spDay; } } //while (dtDay.GetDayOfWeek() != nOleFirstDayOfWeek && dtDay.GetDayOfWeek() != -1) //{ // dtDay -= spDay; //} // populate all grid days for (int nWeek = 0; nWeek < XTP_MAX_WEEKS; nWeek++) { for (int nDay = 0; nDay < XTP_WEEK_DAYS; nDay++) { // create and add new day item CXTPDatePickerItemDay* pDay = new CXTPDatePickerItemDay(m_pControl, this, dtDay); m_arrDays.Add(pDay); // move next day dtDay += spDay; } } } void CXTPDatePickerItemMonth::AutoAdjustLayout(CRect rcClient) { m_rcMonth = rcClient; // calc header rect m_rcHeader = m_rcMonth; m_rcHeader.bottom = m_rcHeader.top + 18; // TODO: change to font height // calc days of week rect m_rcDaysOfWeek = m_rcMonth; m_rcDaysOfWeek.top = m_rcHeader.bottom; m_rcDaysOfWeek.bottom = m_rcDaysOfWeek.top + 18; // TODO: change to font height // draw week numbers m_rcWeekNumbers = m_rcMonth; m_rcWeekNumbers.top = m_rcDaysOfWeek.bottom; m_rcWeekNumbers.right = m_rcWeekNumbers.left + 18; // TODO: change to font width // calc triangles rect m_rcLeftScroll = m_rcHeader; m_rcRightScroll = m_rcHeader; int nScrollWidth = min(m_rcWeekNumbers.Width(), m_rcHeader.Width() / 8); m_rcHeader.left += nScrollWidth; m_rcHeader.right -= nScrollWidth; m_rcLeftScroll.right = m_rcHeader.left; m_rcRightScroll.left = m_rcHeader.right; // calc days display params m_rcDaysArea = m_rcMonth; m_rcDaysArea.top = m_rcDaysOfWeek.bottom; m_rcDaysArea.left = m_rcWeekNumbers.right; m_rcDaysArea.right -= m_rcWeekNumbers.Width(); // calc simple day rect sizes CSize szDay(m_rcDaysArea.Width() / XTP_WEEK_DAYS, m_rcDaysArea.Height() / XTP_MAX_WEEKS); // calc rects for all days CRect rcDay; int nIndex = 0; for (int nWeek = 0; nWeek < XTP_MAX_WEEKS; nWeek++) { for (int nDay = 0; nDay < XTP_WEEK_DAYS; nDay++) { CXTPDatePickerItemDay* pDay = GetDay(nIndex); nIndex++; rcDay.left = m_rcDaysArea.left + nDay * szDay.cx + 1; rcDay.top = m_rcDaysArea.top + nWeek * szDay.cy; rcDay.right = rcDay.left + szDay.cx; rcDay.bottom = rcDay.top + szDay.cy; pDay->SetRect(rcDay); } } } void CXTPDatePickerItemMonth::ByFontAdjustLayout(CRect rcClient) { CWindowDC dc(CWnd::GetDesktopWindow()); CSize szDay(m_pControl->m_pPaintManager->CalcDayRect(&dc)); CSize szHeader(m_pControl->m_pPaintManager->CalcMonthHeaderRect(&dc)); CSize szWeekText(m_pControl->m_pPaintManager->CalcDayOfWeekRect(&dc)); CSize szWeekNumber(m_pControl->m_pPaintManager->CalcWeekNumbersRect(&dc)); m_rcMonth = rcClient; // calc header rect m_rcHeader = m_rcMonth; m_rcHeader.bottom = m_rcHeader.top + szHeader.cy; //m_rcHeader.right = m_rcHeader.left + szHeader.cx; // calc days of week rect m_rcDaysOfWeek = m_rcMonth; m_rcDaysOfWeek.top = m_rcHeader.bottom; //m_rcDaysOfWeek.bottom = m_rcDaysOfWeek.top + 18; // TODO: change to font height m_rcDaysOfWeek.bottom = m_rcDaysOfWeek.top + szWeekText.cy; // draw week numbers m_rcWeekNumbers = m_rcMonth; m_rcWeekNumbers.top = m_rcDaysOfWeek.bottom; //m_rcWeekNumbers.right = m_rcWeekNumbers.left + 18; // TODO: change to font width m_rcWeekNumbers.right = m_rcWeekNumbers.left + szWeekNumber.cx; // calc triangles rect m_rcLeftScroll = m_rcHeader; m_rcRightScroll = m_rcHeader; m_rcLeftScroll.right = m_rcHeader.left+ szWeekNumber.cx + 3; m_rcRightScroll.left = m_rcHeader.right - szWeekNumber.cx - 3; // calc days display params m_rcDaysArea = m_rcMonth; m_rcDaysArea.top = m_rcDaysOfWeek.bottom; m_rcDaysArea.left = m_rcWeekNumbers.right; m_rcDaysArea.right -= m_rcWeekNumbers.Width(); CRect rcDay; int nIndex = 0; for (int nWeek = 0; nWeek < XTP_MAX_WEEKS; nWeek++) { for (int nDay = 0; nDay < XTP_WEEK_DAYS; nDay++) { CXTPDatePickerItemDay* pDay = GetDay(nIndex); nIndex++; rcDay.left = m_rcDaysArea.left + nDay * szDay.cx + 1; rcDay.top = m_rcDaysArea.top + nWeek * szDay.cy; rcDay.right = rcDay.left + szDay.cx ; rcDay.bottom = rcDay.top + szDay.cy; pDay->SetRect(rcDay); } } } void CXTPDatePickerItemMonth::AdjustLayout(CRect rcClient, BOOL bIsAuto) { if (bIsAuto) AutoAdjustLayout(rcClient); else ByFontAdjustLayout(rcClient); } CXTPDatePickerItemDay* CXTPDatePickerItemMonth::GetDay(int nIndex) const { if (nIndex < GetDayCount()) return m_arrDays[nIndex]; return NULL; } int CXTPDatePickerItemMonth::GetDayCount() const { return (int)m_arrDays.GetSize(); } void CXTPDatePickerItemMonth::Draw(CDC* pDC) { // draw header CXTPDatePickerPaintManager* pPaintManager = m_pControl->GetPaintManager(); pPaintManager->DrawMonthHeader(pDC, this); // draw days of week pPaintManager->DrawDaysOfWeek(pDC, this); // draw all days int nDaysCount = GetDayCount(); for (int nIndex = 0; nIndex < nDaysCount; nIndex++) { CXTPDatePickerItemDay* pDay = GetDay(nIndex); pDay->Draw(pDC); } // draw week numbers pPaintManager->DrawWeekNumbers(pDC, this); } void CXTPDatePickerItemMonth::ClearDays() { // cleanup old month array int nOldDayCount = GetDayCount(); for (int nDay = 0; nDay < nOldDayCount; nDay++) { CXTPDatePickerItemDay* pDay = GetDay(nDay); pDay->InternalRelease(); } m_arrDays.RemoveAll(); } void CXTPDatePickerItemMonth::OnLButtonDown(UINT nFlags, CPoint point) { if (!m_pControl) return; BOOL bMultiselect = !!(nFlags & MK_CONTROL) || m_pControl->IsMultiSelectionMode(); // check left scroll item if (m_bShowLeftScroll && !m_rcLeftScroll.IsRectEmpty() && m_rcLeftScroll.PtInRect(point)) { m_pControl->m_mouseMode = CXTPDatePickerControl::mouseScrollingLeft; m_pControl->m_nTimerID = (UINT)m_pControl->SetTimer(XTP_DATEPICKER_TIMERID, XTP_DATEPICKER_TIMER_INTERVAL, NULL); if (m_pControl->m_bYearsTriangle) { if (point.x < m_rcLeftScroll.left + 9) { if (m_dtMonth.GetYear() >= 100 || (m_dtMonth.GetYear() == 100 && m_dtMonth.GetMonth() >= 3)) m_pControl->ScrollLeft(m_pControl->GetMonthDelta()); } else if (point.x > m_rcLeftScroll.right - 9) { if (m_dtMonth.GetYear() >= 101 || (m_dtMonth.GetYear() == 101 && m_dtMonth.GetMonth() >= 3)) m_pControl->ScrollLeft(12 * m_pControl->GetMonthDelta()); } } else { m_pControl->ScrollLeft(m_pControl->GetMonthDelta()); } return; } // check right scroll item if (m_bShowRightScroll && !m_rcRightScroll.IsRectEmpty() && m_rcRightScroll.PtInRect(point)) { m_pControl->m_mouseMode = CXTPDatePickerControl::mouseScrollingRight; m_pControl->m_nTimerID = (UINT)m_pControl->SetTimer(XTP_DATEPICKER_TIMERID, XTP_DATEPICKER_TIMER_INTERVAL, NULL); if (m_pControl->m_bYearsTriangle) { if (point.x < m_rcRightScroll.left + 9) m_pControl->ScrollRight(12 * m_pControl->GetMonthDelta()); else if (point.x > m_rcLeftScroll.right - 9) m_pControl->ScrollRight(m_pControl->GetMonthDelta()); } else { m_pControl->ScrollRight(m_pControl->GetMonthDelta()); } return; } // check header click if (!m_rcHeader.IsRectEmpty() && CRect(m_rcHeader.left + 20, m_rcHeader.top, m_rcHeader.right - 20, m_rcHeader.bottom).PtInRect(point)) //m_rcHeader.PtInRect(point)) { // call month popup list m_pControl->ShowListHeader(m_rcHeader, m_dtMonth); return; } // check week numbers click m_pControl->m_bSelectWeek = !m_rcWeekNumbers.IsRectEmpty() && m_rcWeekNumbers.PtInRect(point); CPoint ptFirstWeekDay(point); ptFirstWeekDay.x = m_rcWeekNumbers.right + 3; // check day item CXTPDatePickerItemDay* pDay = HitTest(m_pControl->m_bSelectWeek ? ptFirstWeekDay : point, FALSE); if (pDay) { m_pControl->ClearFocus(); BOOL bAllowNoncontinuousSelection = m_pControl->IsAllowNoncontinuousSelection(); COleDateTime dtDay(pDay->GetDate()); BOOL bSelected = m_pControl->IsSelected(dtDay); if (m_pControl->m_bSelectWeek) { //week is selected only when all week days are selected for (int i = 0; i < 7; i++) { COleDateTime dtDay_i = dtDay + COleDateTimeSpan(i, 0, 0, 0); bSelected &= m_pControl->IsSelected(dtDay_i); } } if (bSelected && bMultiselect && bAllowNoncontinuousSelection) m_pControl->m_mouseMode = CXTPDatePickerControl::mouseDeselecting; else m_pControl->m_mouseMode = CXTPDatePickerControl::mouseSelecting; if (!bMultiselect || !bAllowNoncontinuousSelection) m_pControl->m_pSelectedDays->Clear(); if (nFlags & MK_SHIFT) { if (m_pControl->m_dtFirstClicked.GetStatus() == COleDateTime::valid) { m_pControl->m_dtLastClicked = dtDay; } else if (m_pControl->m_dtLastClicked.GetStatus() == COleDateTime::valid) { m_pControl->m_dtFirstClicked = m_pControl->m_dtLastClicked; m_pControl->m_dtLastClicked = dtDay; } else if (m_pControl->GetSelRange(m_pControl->m_dtFirstClicked, m_pControl->m_dtLastClicked)) { if (m_pControl->m_dtFirstClicked < dtDay) m_pControl->m_dtLastClicked = dtDay; else m_pControl->m_dtFirstClicked = dtDay; } else { m_pControl->m_dtFirstClicked = dtDay; m_pControl->m_dtLastClicked = dtDay; } } else { m_pControl->m_dtFirstClicked = dtDay; m_pControl->m_dtLastClicked = m_pControl->m_bSelectWeek ? dtDay + COleDateTimeSpan(6, 0, 0, 0) : dtDay; } m_pControl->_RedrawControl(FALSE); } } void CXTPDatePickerItemMonth::OnLButtonUp(UINT /*nFlags*/, CPoint /*point*/) { } void CXTPDatePickerItemMonth::OnMouseMove(UINT /*nFlags*/, CPoint point) { if ((m_pControl->m_mouseMode == CXTPDatePickerControl::mouseDeselecting || m_pControl->m_mouseMode == CXTPDatePickerControl::mouseSelecting) && (m_rcDaysArea.PtInRect(point) || m_rcWeekNumbers.PtInRect(point))) { // check day item CPoint ptWeekBegin(m_rcWeekNumbers.right + 3, point.y); CXTPDatePickerItemDay* pDay = HitTest(m_pControl->m_bSelectWeek ? ptWeekBegin : point, FALSE); if (pDay) { // save old clicked dates COleDateTime dtOldFirstClicked = m_pControl->m_dtFirstClicked; COleDateTime dtOldLastClicked = m_pControl->m_dtLastClicked; // calculate new clicked dates COleDateTime dtDay(pDay->GetDate()); if (m_pControl->m_bSelectWeek) { COleDateTime dtWeekEnd(dtDay + COleDateTimeSpan(6, 0, 0, 0)); if (dtWeekEnd >= m_pControl->m_dtFirstClicked) { if (dtDay.GetDayOfWeek() != m_pControl->m_dtFirstClicked.GetDayOfWeek()) m_pControl->m_dtFirstClicked -= COleDateTimeSpan(6, 0, 0, 0); m_pControl->m_dtLastClicked = dtWeekEnd; } if (dtDay < m_pControl->m_dtFirstClicked) { if (dtDay.GetDayOfWeek() == m_pControl->m_dtFirstClicked.GetDayOfWeek()) m_pControl->m_dtFirstClicked += COleDateTimeSpan(6, 0, 0, 0); m_pControl->m_dtLastClicked = dtDay; } } else { m_pControl->m_dtLastClicked = dtDay; } // update control if needed if (((dtOldLastClicked - m_pControl->m_dtLastClicked).GetDays() != 0) || ((dtOldFirstClicked - m_pControl->m_dtFirstClicked).GetDays() != 0)) { m_pControl->RedrawControl(); } } } } CXTPDatePickerItemDay* CXTPDatePickerItemMonth::HitTest(CPoint point, BOOL bCheckVisible) const { // enumerate month array int nDayCount = GetDayCount(); for (int nDay = 0; nDay < nDayCount; nDay++) { CXTPDatePickerItemDay* pDay = GetDay(nDay); if (pDay && pDay->GetRect().PtInRect(point) && (pDay->IsVisible() || !bCheckVisible)) { return pDay; } } return NULL; } BOOL CXTPDatePickerItemMonth::OnSetCursor(CPoint point) { if (!m_rcWeekNumbers.IsRectEmpty() && m_rcWeekNumbers.PtInRect(point) && m_pControl && m_pControl->GetPaintManager()) { // week selection cursor SetCursor(m_pControl->GetPaintManager()->GetCursorBack()); return TRUE; } return FALSE; }