You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
505 lines
14 KiB
C++
505 lines
14 KiB
C++
// 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;
|
|
}
|