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.

2466 lines
55 KiB
C++

// XTPDatePickerControl.cpp: implementation of the CXTPDatePickerControl 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 "Resource.h"
#include "Common/XTPDrawHelpers.h"
#include "Common/XTPImageManager.h"
#include "Common/XTPSystemHelpers.h"
#include "Common/XTPResourceImage.h"
#include "Common/XTPColorManager.h"
#include "Common/XTPNotifyConnection.h"
#include "XTPCalendarDefines.h"
#include "XTPCalendarMsgNotifier.h"
#include "XTPCalendarUtils.h"
#include "XTPDatePickerItemMonth.h"
#include "XTPDatePickerPaintManager.h"
#include "XTPDatePickerDaysCollection.h"
#include "XTPDatePickerList.h"
#include "XTPDatePickerItemDay.h"
#include "XTPDatePickerControl.h"
#include "XTPDatePickerNotifications.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#pragma warning(disable: 4571) // warning C4571: catch(...) blocks compiled with /EHs do not catch or re-throw Structured Exceptions
// Custom class name for the Date Picker control window
const TCHAR XTP_DATEPICKERCTRL_CLASSNAME[] = _T("XTPDatePicker");
//////////////////////////////////////////////////////////////////////////
// CXTPDatePickerButtons
int CXTPDatePickerButtons::GetVisibleButtonCount() const
{
int nCount = 0;
for (int i = 0; i < (int)GetSize(); i++)
{
if (GetAt(i)->m_bVisible) nCount++;
}
return nCount;
}
CXTPDatePickerButton* CXTPDatePickerButtons::Find(int nID) const
{
for (int i = 0; i < (int)GetSize(); i++)
{
if (GetAt(i)->m_nID == nID)
return GetAt(i);
}
return NULL;
}
CXTPDatePickerButton* CXTPDatePickerButtons::HitTest(CPoint point) const
{
for (int i = 0; i < (int)GetSize(); i++)
{
if (GetAt(i)->m_bVisible && GetAt(i)->m_rcButton.PtInRect(point))
return GetAt(i);
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////
// XTP_DAYITEM_METRICS
XTP_DAYITEM_METRICS::XTP_DAYITEM_METRICS()
{
clrForeground = 0;
clrBackground = 0;
}
CFont* XTP_DAYITEM_METRICS::GetFont()
{
return &m_fntText;
}
void XTP_DAYITEM_METRICS::SetFont(CFont* pFont)
{
ASSERT_VALID(pFont);
if (!pFont)
return;
// set new font
LOGFONT lf;
pFont->GetLogFont(&lf);
m_fntText.DeleteObject();
m_fntText.CreateFontIndirect(&lf);
}
CXTPDatePickerButton::CXTPDatePickerButton()
{
m_rcButton.SetRectEmpty();
m_bVisible = TRUE;
m_bPressed = FALSE;
m_bHighlight = FALSE;
m_nID = 0;
}
CString CXTPDatePickerButton::GetCaption() const
{
if (m_strCaption.IsEmpty())
return CXTPCalendarUtils::LoadString(m_nID);
return m_strCaption;
}
void CXTPDatePickerButton::SetCaption(LPCTSTR pcszCaption)
{
m_strCaption = pcszCaption;
}
//////////////////////////////////////////////////////////////////////////////
// CXTPDatePickerControl
CXTPDatePickerControl::CXTPDatePickerControl()
{
m_pConnection = new CXTPNotifyConnection();
m_pSink = new CXTPNotifySink();
RegisterWindowClass();
m_pfnCallback = NULL;
m_pCallbackParam = NULL;
m_nLockUpdateCount = 0;
m_lcidActiveLocale = CXTPCalendarUtils::GetActiveLCID();
m_pPaintManager = NULL;
SetTheme(NULL);// set default paint manager
//SetTheme(new CXTPDatePickerThemeOffice2007());
m_bAutoSize = TRUE;
m_bRestrictMode = FALSE;
m_mouseMode = mouseNothing;
m_nTimerID = 0;
m_bIsModal = FALSE;
m_nMaxSelectionDays = XTP_SELECTION_INFINITE;
m_bSelectWeek = FALSE;
m_bRightToLeft = FALSE;
m_bShowWeekNumbers = FALSE;
m_nRows = 1;
m_nColumns = 1;
m_nDesiredRows = 1;
m_nDesiredColumns = 1;
m_nFirstDayOfWeek = 2;
m_nFirstWeekOfYearDays = 1;
m_nMonthDelta = 0;
m_bHighlightToday = TRUE;
m_bChanged = TRUE;
m_dtToday = COleDateTime::GetCurrentTime();
m_dtFirstMonth.SetDate(m_dtToday.GetYear(), m_dtToday.GetMonth(), 1);
m_dtMinRange.SetStatus(COleDateTime::null);
m_dtMaxRange.SetStatus(COleDateTime::null);
m_rcControl.SetRectEmpty();
m_rcGrid.SetRectEmpty();
m_bShowNonMonthDays = TRUE;
m_borderStyle = xtpDatePickerBorder3D;
m_pButtonCaptured = NULL;
AddButton(XTP_IDS_DATEPICKER_TODAY);
AddButton(XTP_IDS_DATEPICKER_NONE);
m_pListControl = NULL;
m_pSelectedDays = new CXTPDatePickerDaysCollection(this);
m_arMonthNames = new CString[12];
m_arDayOfWeekNames = new CString[7];
m_bAllowNoncontinuousSelection = TRUE;
m_bMultiSelectionMode = FALSE;
m_bDeleteOnFinalRelease = FALSE;
m_bYearsTriangle = FALSE;
InitNames();
ClearFocus();
Populate();
//-----------------------------------------------------------------------
XTPCalendarMsgNotifier()->Advise(this, WM_TIMECHANGE);
if (XTPResourceImages() && XTPResourceImages()->GetConnection())
{
m_pSink->Advise(XTPResourceImages()->GetConnection(), XTP_NC_COMMON_RESOURCEIMAGES_CHANGED,
CreateNotfySinkClassDelegate(this, &CXTPDatePickerControl::OnEventResourceImagesChanged));
}
}
CXTPDatePickerControl::~CXTPDatePickerControl()
{
XTPCalendarMsgNotifier()->Unadvise(this);
ClearMonths();
CMDTARGET_RELEASE(m_pPaintManager);
if (m_pListControl)
{
m_pListControl->DestroyWindow();
delete m_pListControl;
}
CMDTARGET_RELEASE(m_pSelectedDays);
if (m_nTimerID != 0 && m_hWnd)
KillTimer(m_nTimerID);
DestroyWindow();
for (int i = 0; i < GetButtonCount(); i++)
delete m_arrButtons[i];
delete[] m_arDayOfWeekNames;
delete[] m_arMonthNames;
CMDTARGET_RELEASE(m_pConnection);
m_pSink->Delete();
}
void CXTPDatePickerControl::OnDestroy()
{
if (m_bIsModal)
{
if (ContinueModal()) // skip if EndModalLoop has already called
{
EndModalLoop(IDABORT);
}
}
CWnd::OnDestroy();
}
void CXTPDatePickerControl::OnEventResourceImagesChanged(XTP_NOTIFY_CODE Event, WPARAM /*wParam*/, LPARAM /*lParam*/)
{
ASSERT(Event == XTP_NC_COMMON_RESOURCEIMAGES_CHANGED);
if (Event == XTP_NC_COMMON_RESOURCEIMAGES_CHANGED && GetPaintManager()->GetPaintTheme() == xtpCalendarThemeResource)
{
GetPaintManager()->RefreshMetrics();
_RedrawControl(FALSE);
}
}
void CXTPDatePickerControl::AddButton(UINT nID)
{
CXTPDatePickerButton* pButton = new CXTPDatePickerButton();
pButton->m_nID = nID;
m_arrButtons.Add(pButton);
}
BOOL CXTPDatePickerControl::IsTodayButtonVisible()
{
CXTPDatePickerButton* pButton = m_arrButtons.Find(XTP_IDS_DATEPICKER_TODAY);
return pButton ? pButton->m_bVisible : FALSE;
}
BOOL CXTPDatePickerControl::IsNoneButtonVisible()
{
CXTPDatePickerButton* pButton = m_arrButtons.Find(XTP_IDS_DATEPICKER_NONE);
return pButton ? pButton->m_bVisible : FALSE;
}
void CXTPDatePickerControl::SetTheme(CXTPDatePickerPaintManager* pPaintManager)
{
// set default
if (!pPaintManager)
pPaintManager = new CXTPDatePickerPaintManager();
CMDTARGET_RELEASE(m_pPaintManager);
m_pPaintManager = pPaintManager;
if (m_pPaintManager)
{
m_pPaintManager->RefreshMetrics();
}
_RedrawControl(FALSE);
}
void CXTPDatePickerControl::RedrawControl()
{
_RedrawControl(TRUE);
}
void CXTPDatePickerControl::_RedrawControl(BOOL bUpdateNow)
{
m_bChanged = TRUE;
if (GetSafeHwnd() && (m_nLockUpdateCount == 0))
{
Invalidate(FALSE);
if (bUpdateNow)
{
UpdateWindow();
}
}
}
BEGIN_MESSAGE_MAP(CXTPDatePickerControl, CWnd)
//{{AFX_MSG_MAP(CXTPDatePickerControl)
ON_WM_CREATE()
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_MESSAGE(WM_PRINTCLIENT, OnPrintClient)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDBLCLK()
ON_WM_CAPTURECHANGED()
ON_WM_CANCELMODE()
ON_WM_MOUSEMOVE()
ON_WM_TIMER()
ON_WM_TIMECHANGE()
ON_WM_SIZE()
ON_WM_SYSCOLORCHANGE()
ON_WM_KEYDOWN()
ON_WM_SETCURSOR()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_WM_GETDLGCODE()
ON_WM_DESTROY()
ON_WM_ENABLE()
//}}AFX_MSG_MAP
ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CXTPDatePickerControl message handlers
BOOL CXTPDatePickerControl::OnEraseBkgnd(CDC* /*pDC*/)
{
return TRUE;
}
int CXTPDatePickerControl::OnCreate(LPCREATESTRUCT lp)
{
int nRet = CWnd::OnCreate(lp);
CXTPClientRect rc(this);
AdjustLayout(rc);
if (m_bRightToLeft)
{
SetLayoutRTL(TRUE);
}
return nRet;
}
void CXTPDatePickerControl::PreSubclassWindow()
{
CXTPClientRect rc(this);
AdjustLayout(rc);
}
BOOL CXTPDatePickerControl::GoModal(const RECT& rect, CWnd* pParentWnd)
{
if (!pParentWnd)
pParentWnd = AfxGetMainWnd();
CRect rcScreen(rect);
if (!::IsWindow(m_hWnd) && !CreateEx(WS_EX_TOOLWINDOW, XTP_DATEPICKERCTRL_CLASSNAME, NULL, pParentWnd ? WS_CHILD : WS_POPUP, rcScreen, pParentWnd, 0))
return FALSE;
// Enable this window
EnableWindow(TRUE);
HWND hwndFocusWnd = ::SetFocus(m_hWnd);
if (pParentWnd)
{
SetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT, 0);
ModifyStyle(WS_CHILD, WS_POPUP);
SetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT, (LONG_PTR)pParentWnd->m_hWnd);
}
SetWindowPos(&CWnd::wndTopMost, rcScreen.left, rcScreen.top, rcScreen.Width(), rcScreen.Height(), SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
SetCapture();
SendNotification(XTP_NC_DATEPICKERBEFOREGOMODAL);
SendMessageToParent(XTP_NC_DATEPICKERBEFOREGOMODAL);
m_bIsModal = TRUE;
m_nFlags |= WF_CONTINUEMODAL;
int nResult = m_nModalResult;
if (ContinueModal())
{
// enter modal loop
DWORD dwFlags = MLF_SHOWONIDLE;
if (GetStyle() & DS_NOIDLEMSG)
dwFlags |= MLF_NOIDLEMSG;
nResult = RunModalLoop(dwFlags);
}
ReleaseCapture();
DestroyWindow();
m_bIsModal = FALSE;
if (hwndFocusWnd && ::IsWindow(hwndFocusWnd) && ::IsWindowVisible(hwndFocusWnd))
::SetFocus(hwndFocusWnd);
return (nResult == IDOK);
}
CSize CXTPDatePickerControl::SetGridDimentions(CRect rcClient)
{
CWindowDC dc(GetOwner());
CSize szMonth(m_pPaintManager->CalcMonthRect(&dc));
szMonth.cy += 2;
m_nRows = max(1, rcClient.Height() / szMonth.cy);
m_nColumns = max(1, rcClient.Width() / szMonth.cx);
if (m_dtMaxRange.GetStatus() == COleDateTime::valid)
{
int nMaxRangeMonths = (m_dtMaxRange.GetYear() * 12 + m_dtMaxRange.GetMonth()) -
(m_dtFirstMonth.GetYear() * 12 + m_dtFirstMonth.GetMonth()) + 1;
if (m_dtMinRange.GetStatus() == COleDateTime::valid)
{
int nTotalMaxRangeMonths = (m_dtMaxRange.GetYear() * 12 + m_dtMaxRange.GetMonth()) -
(m_dtMinRange.GetYear() * 12 + m_dtMinRange.GetMonth()) + 1;
if (nTotalMaxRangeMonths == 12 && m_nColumns >= 6 && m_nRows >= 2)
{
m_nColumns = 6;
m_nRows = 2;
}
if (nTotalMaxRangeMonths == 12 && m_nColumns == 5 && m_nRows > 2)
{
m_nColumns = 4;
m_nRows = 3;
}
while (m_nRows * m_nColumns > nTotalMaxRangeMonths)
{
if (m_nRows > m_nColumns)
{
if (m_nRows > 1)
m_nRows--;
else
break;
}
else
{
if (m_nColumns > 1)
m_nColumns--;
else
break;
}
//original logic
//if (m_nRows > 1)
// m_nRows--;
//else if (m_nColumns > 1)
// m_nColumns--;
//else
// break;
//opposite logic
//if (m_nColumns > 1)
// m_nColumns--;
//else if (m_nRows > 1)
// m_nRows--;
//else
// break;
}
}
if (m_nRows * m_nColumns > nMaxRangeMonths)
{
ShiftDate(m_dtFirstMonth, nMaxRangeMonths - m_nRows * m_nColumns);
}
if (m_dtMinRange.GetStatus() == COleDateTime::valid &&
m_dtFirstMonth < m_dtMinRange)
{
m_dtFirstMonth = m_dtMinRange;
while (m_nRows * m_nColumns > nMaxRangeMonths)
{
if (m_nRows > m_nColumns)
{
if (m_nRows > 1)
m_nRows--;
else
break;
}
else
{
if (m_nColumns > 1)
m_nColumns--;
else
break;
}
//original logic
//if (m_nRows > 1)
// m_nRows--;
//else if (m_nColumns > 1)
// m_nColumns--;
//else
// break;
}
}
}
return szMonth;
}
void CXTPDatePickerControl::AdjustLayout(CRect rcClient)
{
if (!GetSafeHwnd())
return;
if (m_lcidActiveLocale != CXTPCalendarUtils::GetActiveLCID())
{
m_lcidActiveLocale = CXTPCalendarUtils::GetActiveLCID();
InitNames();
}
m_dtToday = COleDateTime::GetCurrentTime();
m_rcControl = rcClient;
CSize szMonth(0, 0);
CRect rcMonth(0, 0, 0, 0);
//get button size
CSize szButton(CalcButtonSize());
m_rcGrid.CopyRect(&m_rcControl);
m_pPaintManager->DrawBorder(0, this, m_rcGrid, FALSE);
if (m_arrButtons.GetVisibleButtonCount() > 0)
m_rcGrid.bottom -= szButton.cy;
if (!m_bAutoSize)
{
szMonth.cx = m_rcGrid.Width() / m_nColumns;
szMonth.cy = m_rcGrid.Height() / m_nRows;
}
else
{
szMonth = SetGridDimentions(m_rcGrid);
if (m_bRestrictMode)
{
m_nRows = min(m_nDesiredRows, m_nRows);
m_nColumns = min(m_nDesiredColumns, m_nColumns);
}
CSize szGrid (szMonth.cx * m_nColumns, szMonth.cy * m_nRows);
int nXOffset = max(0, (m_rcGrid.left + m_rcGrid.right - szGrid.cx) / 2);
int nYOffset = max(0, (m_rcGrid.top + m_rcGrid.bottom - szGrid.cy) / 2);
m_rcGrid = CRect(CPoint(nXOffset, nYOffset), szGrid);
ClearMonths();
CreateMonthArray();
} // else auto end
CalcButtonBandRect();
int nIndex = 0;
for (int nRow = 0; nRow < m_nRows; nRow++)
{
for (int nCol = 0; nCol < m_nColumns; nCol++)
{
rcMonth = CRect(CPoint(m_rcGrid.left + nCol * szMonth.cx, m_rcGrid.top + nRow * szMonth.cy), szMonth);
rcMonth.DeflateRect(1, 1);
// get next month item
CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nIndex);
nIndex++;
// adjust internal month layout
pMonth->AdjustLayout(rcMonth, !m_bAutoSize);
}
}
m_bChanged = TRUE;
}
void CXTPDatePickerControl::OnPaint()
{
CPaintDC dc(this); // device context for painting
CXTPClientRect rc(this);
// Check cached bitmap
if (!m_bChanged && m_bmpCache.GetSafeHandle() != 0)
{
CXTPCompatibleDC memDC(&dc, &m_bmpCache);
dc.BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY);
}
else
{
CDC memDC;
memDC.CreateCompatibleDC(&dc);
m_bmpCache.DeleteObject();
m_bmpCache.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
CBitmap* pOldBitmap = memDC.SelectObject(&m_bmpCache);
OnDraw(&memDC);
if (!IsWindowEnabled())
{
XTPImageManager()->DisableBitmap(memDC, rc, XTP_CALENDAR_DISABLED_COLOR_LIGHT, XTP_CALENDAR_DISABLED_COLOR_DARK);
}
dc.BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY);
memDC.SelectObject(pOldBitmap);
// update flag
m_bChanged = FALSE;
}
}
LRESULT CXTPDatePickerControl::OnPrintClient(WPARAM wParam, LPARAM /*lParam*/)
{
CDC* pDC = CDC::FromHandle((HDC)wParam);
if (pDC)
{
OnDraw(pDC);
}
return TRUE;
}
void CXTPDatePickerControl::OnDraw(CDC* pDC)
{
CXTPClientRect rcClient(this);
// draw background
m_pPaintManager->DrawBackground(pDC, rcClient);
// draw all month items in the collection
int nMonthCount = (int)m_arrMonths.GetSize();
for (int nIndex = 0; nIndex < nMonthCount; nIndex++)
{
// get next month item
CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nIndex);
// draw it
pMonth->Draw(pDC);
}
// draw today/none buttons
DrawButtons(pDC);
// draw border
m_pPaintManager->DrawBorder(pDC, this, rcClient, TRUE);
}
UINT CXTPDatePickerControl::OnGetDlgCode()
{
return DLGC_WANTARROWS /*| DLGC_WANTTAB | DLGC_WANTALLKEYS*/;
}
void CXTPDatePickerControl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
#ifdef XTP_DATEPICKER_SITENOTIFY_KEY
if (!XTP_DATEPICKER_SITENOTIFY_KEY(this, TRUE, nChar))
return;
#endif
if (nChar == 0)
return;
if (nChar == VK_RETURN || nChar == VK_ESCAPE)
{
if (m_bIsModal)
{
if (ContinueModal()) // skip if EndModalLoop has already called
{
EndModalLoop(nChar == VK_RETURN ? IDOK : IDCANCEL);
}
return;
}
}
else if (nChar == VK_LEFT || nChar == VK_RIGHT || nChar == VK_UP ||
nChar == VK_DOWN || nChar == VK_PRIOR || nChar == VK_NEXT ||
nChar == VK_HOME || nChar == VK_END ||
nChar == VK_SPACE)
{
CXTPSelectionHelper _selector(this);
BOOL bIsShift = (GetKeyState(VK_SHIFT) < 0);
BOOL bIsCtrl = (GetKeyState(VK_CONTROL) < 0) || IsMultiSelectionMode();
XTPDrawHelpers()->KeyToLayout(this, nChar);
if (nChar == VK_RIGHT)
{
_selector.MoveFocus(stepDay, dirNext, bIsShift, bIsCtrl);
}
else if (nChar == VK_DOWN)
{
_selector.MoveFocus(stepWeek, dirNext, bIsShift, bIsCtrl);
}
else if (nChar == VK_NEXT && !bIsCtrl)
{
_selector.MoveFocus(stepMonth, dirNext, FALSE, FALSE);
}
else if (nChar == VK_NEXT && bIsCtrl)
{
_selector.MoveFocus(stepYear, dirNext, FALSE, FALSE);
}
//*****
else if (nChar == VK_LEFT)
{
_selector.MoveFocus(stepDay, dirPrev, bIsShift, bIsCtrl);
}
else if (nChar == VK_UP)
{
_selector.MoveFocus(stepWeek, dirPrev, bIsShift, bIsCtrl);
}
else if (nChar == VK_PRIOR && !bIsCtrl)
{
_selector.MoveFocus(stepMonth, dirPrev, FALSE, FALSE);
}
else if (nChar == VK_PRIOR && bIsCtrl)
{
_selector.MoveFocus(stepYear, dirPrev, FALSE, FALSE);
}
//***
else if (nChar == VK_HOME && !bIsCtrl)
{
_selector.MoveFocus(stepWeekBE, dirPrev, FALSE, FALSE);
}
else if (nChar == VK_HOME && bIsCtrl)
{
_selector.MoveFocus(stepMonthBE, dirPrev, FALSE, FALSE);
}
//***
else if (nChar == VK_END && !bIsCtrl)
{
_selector.MoveFocus(stepWeekBE, dirNext, FALSE, FALSE);
}
else if (nChar == VK_END && bIsCtrl)
{
_selector.MoveFocus(stepMonthBE, dirNext, FALSE, FALSE);
}
//***
else if (nChar == VK_SPACE && bIsCtrl)
{
_selector.SelUnselFocus();
}
//***
_selector._TmpSaveFocus();
m_nLockUpdateCount++;
// fire selection changed
SendNotification(XTP_NC_DATEPICKERSELECTIONCHANGED);
SendMessageToParent(XTP_NC_DATEPICKER_SELECTION_CHANGED);
//***
_selector._TmpRestoreFocus();
m_nLockUpdateCount--;
//-------------------
EnsureVisibleFocus();
//--------------
RedrawControl();
}
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CXTPDatePickerControl::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_bIsModal && !m_rcControl.PtInRect(point))
{
if (ContinueModal()) // skip if EndModalLoop has already called
{
EndModalLoop(IDCANCEL);
}
return;
}
if (!m_bIsModal)
{
SetCapture();
}
SetFocus();
CXTPDatePickerItemMonth* pMonth = HitTest(point);
if (pMonth)
{
pMonth->OnLButtonDown(nFlags, point);
}
// process buttons
m_pButtonCaptured = m_arrButtons.HitTest(point);
ProcessButtons(point);
CWnd::OnLButtonDown(nFlags, point);
}
void CXTPDatePickerControl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CXTPDatePickerItemMonth* pMonth = HitTest(point);
if (pMonth)
{
pMonth->OnLButtonDown(nFlags, point);
}
m_pButtonCaptured = m_arrButtons.HitTest(point);
ProcessButtons(point);
CWnd::OnLButtonDblClk(nFlags, point);
}
void CXTPDatePickerControl::OnLButtonUp(UINT nFlags, CPoint point)
{
// kill timer
if (m_nTimerID != 0)
{
KillTimer(m_nTimerID);
m_nTimerID = 0;
}
// logic message processing
if (m_mouseMode == mouseTrackingHeaderList)
{
// reset mouse mode
m_mouseMode = mouseNothing;
if (m_pListControl)
{
int nDelta = m_pListControl->GetMonthInterval();
// destroy list control
m_pListControl->DestroyWindow();
delete m_pListControl;
m_pListControl = NULL;
// scroll on selected months count
if (nDelta < 0)
ScrollLeft(-nDelta);
else if (nDelta > 0)
ScrollRight(nDelta);
}
}
else
{
// forward message to appropriate month
CXTPDatePickerItemMonth* pMonth = HitTest(point);
if (pMonth)
{
pMonth->OnLButtonUp(nFlags, point);
}
// Update selection
BOOL bSelecting = m_mouseMode == mouseSelecting;
BOOL bDeselecting = m_mouseMode == mouseDeselecting;
if (bSelecting || bDeselecting)
{
int nDay = (m_dtLastClicked - m_dtFirstClicked).GetDays();
for (; abs(nDay) >= 0; nDay += nDay > 0 ? -1 : 1)
{
COleDateTime dtSelect(m_dtFirstClicked);
dtSelect += nDay;
if (bDeselecting)
{
m_pSelectedDays->Remove(dtSelect);
}
else if (bSelecting && IsSelected(dtSelect))
{
m_pSelectedDays->Add(dtSelect);
}
if (nDay == 0)
break;
}
// reset mouse mode
m_mouseMode = mouseNothing;
// fire selection changed
SendNotification(XTP_NC_DATEPICKERSELECTIONCHANGED);
SendMessageToParent(XTP_NC_DATEPICKER_SELECTION_CHANGED);
_EndModalIfNeed();
}
}
//release resources
if (!m_bIsModal)
ReleaseCapture();
// process buttons
m_pButtonCaptured = NULL;
ProcessButtons(point);
// reset mouse mode
m_mouseMode = mouseNothing;
CWnd::OnLButtonUp(nFlags, point);
}
void CXTPDatePickerControl::OnCaptureChanged(CWnd* pWnd)
{
// kill timer
if (m_nTimerID != 0)
{
KillTimer(m_nTimerID);
m_nTimerID = 0;
}
// logic message processing
if (m_mouseMode == mouseTrackingHeaderList)
{
// reset mouse mode
m_mouseMode = mouseNothing;
if (m_pListControl)
{
if (m_pListControl->GetSafeHwnd())
m_pListControl->DestroyWindow();
delete m_pListControl;
m_pListControl = NULL;
}
}
m_pButtonCaptured = NULL;
if (m_bIsModal)
{
if (ContinueModal()) // skip if EndModalLoop has already called
{
EndModalLoop(IDOK);
}
}
CWnd::OnCaptureChanged(pWnd);
}
void CXTPDatePickerControl::OnCancelMode()
{
CWnd::OnCancelMode();
}
void CXTPDatePickerControl::OnMouseLeave()
{
TRACKMOUSEEVENT tre;
tre.dwFlags = TME_CANCEL;
tre.hwndTrack = this->m_hWnd;
tre.dwHoverTime = HOVER_DEFAULT;
tre.cbSize = sizeof(tre);
_TrackMouseEvent(&tre);
ProcessButtons(CPoint(-1, -1));
}
void CXTPDatePickerControl::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_mouseMode == mouseTrackingHeaderList)
{
if (m_pListControl)
{
m_pListControl->OnMouseMove(nFlags, point);
}
}
else
{
// forward message to appropriate month
CXTPDatePickerItemMonth* pMonth = HitTest(point);
if (pMonth)
pMonth->OnMouseMove(nFlags, point);
}
ProcessButtons(point);
// standard processing
CWnd::OnMouseMove(nFlags, point);
TRACKMOUSEEVENT tre;
tre.dwFlags = TME_LEAVE;
tre.hwndTrack = this->m_hWnd;
tre.dwHoverTime = HOVER_DEFAULT;
tre.cbSize = sizeof(tre);
_TrackMouseEvent(&tre);
// fire mouse move
DWORD dwPoint = MAKELONG(point.x, point.y);
SendNotification(XTP_NC_DATEPICKERMOUSEMOVE, dwPoint);
}
BOOL CXTPDatePickerControl::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/)
{
WNDCLASS wndcls;
if (hInstance == NULL) hInstance = AfxGetInstanceHandle();
if (!(::GetClassInfo(hInstance, XTP_DATEPICKERCTRL_CLASSNAME, &wndcls)))
{
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInstance;
wndcls.hIcon = NULL;
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = XTP_DATEPICKERCTRL_CLASSNAME;
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
BOOL CXTPDatePickerControl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
if (!CWnd::Create(XTP_DATEPICKERCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID, pContext))
return FALSE;
return TRUE;
}
void CXTPDatePickerControl::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
CXTPClientRect rc(this);
CRect rcClient(0, 0, 0, 0);
GetClientRect(&rcClient);
AdjustLayout(rc);
}
void CXTPDatePickerControl::ClearMonths()
{
// cleanup old month array
int nOldMonthCount = (int)m_arrMonths.GetSize();
for (int nMonth = 0; nMonth < nOldMonthCount; nMonth++)
{
CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nMonth);
pMonth->InternalRelease();
}
m_arrMonths.RemoveAll();
}
void CXTPDatePickerControl::CreateMonthArray()
{
CString s; s = m_dtFirstMonth.Format();
COleDateTime dtNextMonth(m_dtFirstMonth);
for (int nRow = 0; nRow < m_nRows; nRow++)
{
for (int nCol = 0; nCol < m_nColumns; nCol++)
{
//int nIndex = nRow * m_nRows + nCol;
// create next month item
CXTPDatePickerItemMonth* pMonth = new CXTPDatePickerItemMonth(this, dtNextMonth, nRow, nCol);
// add it to the array
m_arrMonths.Add(pMonth);
// go to the next month
if (dtNextMonth.GetMonth() < 12)
dtNextMonth.SetDate(dtNextMonth.GetYear(), dtNextMonth.GetMonth() + 1, 1);
else
dtNextMonth.SetDate(dtNextMonth.GetYear() + 1, 1, 1);
}
}
// set first month and last month defaults
int nMonthCount = (int)m_arrMonths.GetSize();
if (nMonthCount > 0)
{
CXTPDatePickerItemMonth* pFirstMonth = m_arrMonths.GetAt(0);
CXTPDatePickerItemMonth* pLastMonth = m_arrMonths.GetAt(nMonthCount - 1);
CXTPDatePickerItemMonth* pLastMonthTopRow = m_arrMonths.GetAt(m_nColumns - 1);
// by default set show previous days for first month and show following days for last month
pFirstMonth->SetShowDaysBefore(m_bShowNonMonthDays);
pLastMonth->SetShowDaysAfter(m_bShowNonMonthDays);
// set triangles showing
BOOL bScrollLeft = TRUE;
if (m_dtMinRange.GetStatus() == COleDateTime::valid
&& pFirstMonth->GetMonth() <= m_dtMinRange)
{
bScrollLeft = FALSE;
}
pFirstMonth->SetShowScrolling(bScrollLeft, pFirstMonth->GetShowRightScroll());
BOOL bScrollRight = TRUE;
if (m_dtMaxRange.GetStatus() == COleDateTime::valid
&& (DATE)pLastMonth->GetMonth() + 30.0 >= (DATE)m_dtMaxRange)
{
bScrollRight = FALSE;
}
pLastMonthTopRow->SetShowScrolling(pLastMonthTopRow->GetShowLeftScroll(), bScrollRight);
}
}
void CXTPDatePickerControl::Populate()
{
// cleanup old month array
ClearMonths();
// add all month items in the grid to the array
// and set first month and last month defaults
CreateMonthArray();
// redraw control image
if (!m_rcControl.IsRectEmpty())
AdjustLayout(m_rcControl);
_RedrawControl(FALSE);
///////////////////////////////
ClearFocus();
// m_pSelectedDays->Clear();
///////////////////////////////
SendNotification(XTP_NC_DATEPICKERMONTHCHANGED);
SendMessageToParent(XTP_NC_DATEPICKERMONTHCHANGED);
}
void CXTPDatePickerControl::GetDayMetrics(COleDateTime& dtDay, XTP_DAYITEM_METRICS* pDayMetics)
{
WPARAM wprmDay = (XTP_DATE_VALUE)(DATE)dtDay;
SendNotification(XTP_NC_DATEPICKERGETDAYMETRICS, wprmDay, (LPARAM)pDayMetics);
if (m_pfnCallback)
{
try
{
m_pfnCallback(this, dtDay, pDayMetics, m_pCallbackParam);
}
catch(...)
{
ASSERT(FALSE);
}
}
}
void CXTPDatePickerControl::SetGridSize(int nRows, int nCols, BOOL bRestrictMode)
{
m_nDesiredRows = nRows;
m_nDesiredColumns = nCols;
m_nRows = nRows;
m_nColumns = nCols;
m_bRestrictMode = bRestrictMode;
Populate();
}
void CXTPDatePickerControl::SetHighlightToday(BOOL bValue)
{
m_bHighlightToday = bValue;
_RedrawControl(FALSE);
}
void CXTPDatePickerControl::SetShowWeekNumbers(BOOL bValue)
{
m_bShowWeekNumbers = bValue;
AdjustLayout(m_rcControl);
_RedrawControl(FALSE);
}
CSize CXTPDatePickerControl::CalcButtonSize() const
{
// get button size
CWindowDC dc(GetDesktopWindow());
CXTPFontDC fnt(&dc, m_pPaintManager->GetButtonFont());
CSize szButton(0, 0);
for (int i = 0; i < GetButtonCount(); i++)
{
CSize sz = dc.GetTextExtent(GetButton(i)->GetCaption());
szButton.cx = max(szButton.cx, sz.cx + 12);
szButton.cy = max(szButton.cy, sz.cy + 6);
}
return szButton;
}
void CXTPDatePickerControl::SetButtonRect()
{
CSize szButton(CalcButtonSize());
int nGap = 10;
int nButtonLen = szButton.cx + nGap;
int nVisibleCount = m_arrButtons.GetVisibleButtonCount();
int nLeft = m_rcGrid.CenterPoint().x - (nButtonLen * nVisibleCount - nGap)/2;
for (int i = 0; i < GetButtonCount(); i++)
{
CXTPDatePickerButton* pButton = GetButton(i);
if (!pButton->m_bVisible) continue;
pButton->m_rcButton = CRect(CPoint(nLeft, m_rcGrid.bottom + 1), szButton);
nLeft += nButtonLen;
}
}
void CXTPDatePickerControl::CalcButtonBandRect()
{
SetButtonRect();
}
void CXTPDatePickerControl::DrawButtons(CDC* pDC)
{
for (int i = 0; i < GetButtonCount(); i++)
{
CXTPDatePickerButton* pButton = GetButton(i);
if (pButton->m_bVisible)
m_pPaintManager->DrawButton(pDC, pButton->m_rcButton, pButton->GetCaption(), pButton->m_bPressed, pButton->m_bHighlight);
}
}
CXTPDatePickerItemMonth* CXTPDatePickerControl::HitTest(CPoint ptMouse) const
{
// enumerate all month items in the collection
int nMonthCount = (int)m_arrMonths.GetSize();
for (int nIndex = 0; nIndex < nMonthCount; nIndex++)
{
CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nIndex);
if (pMonth && pMonth->m_rcMonth.PtInRect(ptMouse))
return pMonth;
}
return NULL;
}
void CXTPDatePickerControl::ScrollLeft(int nMonthCount)
{
int nYear = m_dtFirstMonth.GetYear();
int nMonth = m_dtFirstMonth.GetMonth();
if (nYear < 100 || (nYear == 100 && nMonth <= 2))
return;
int nYearNew = nYear - nMonthCount / 12;
int nMonthNew = nMonth - nMonthCount % 12;
if (nMonthNew < 1)
{
nMonthNew += 12;
nYearNew--;
}
ASSERT(nMonthNew >= 1 && nMonthNew <= 12);
if (m_dtMinRange.GetStatus() == COleDateTime::valid)
{
if (nYearNew < m_dtMinRange.GetYear())
{
nYearNew = m_dtMinRange.GetYear();
nMonthNew = m_dtMinRange.GetMonth();
}
if (m_dtMinRange.GetYear() == nYearNew)
{
if (nMonthNew < m_dtMinRange.GetMonth())
nMonthNew = m_dtMinRange.GetMonth();
}
}
m_dtFirstMonth.SetDate(nYearNew, nMonthNew, 1);
Populate();
}
void CXTPDatePickerControl::ScrollRight(int nMonthCount)
{
int nYear = m_dtFirstMonth.GetYear();
int nMonth = m_dtFirstMonth.GetMonth();
int nYearNew = nYear + nMonthCount / 12;
int nMonthNew = nMonth + nMonthCount % 12;
if (nMonthNew > 12)
{
nMonthNew -= 12;
nYearNew++;
}
if (m_dtMaxRange.GetStatus() == COleDateTime::valid)
{
int nLeftYear = m_dtMaxRange.GetYear();
int nMaxMonth = m_dtMaxRange.GetMonth();
int nLeftMonth = nMaxMonth - m_nRows * m_nColumns + 1;
if (nLeftMonth < 1)
{
nLeftYear -= (-nLeftMonth) / 12 + 1;
nLeftMonth = -(((-nLeftMonth) % 12) - 12);
}
if (nYearNew > nLeftYear)
{
nYearNew = nLeftYear;
nMonthNew = nLeftMonth;
}
if (nLeftYear == nYearNew)
{
if (nMonthNew > nLeftMonth)
nMonthNew = nLeftMonth;
}
}
m_dtFirstMonth.SetDate(nYearNew, nMonthNew, 1);
ScrollLeft(0); // adjust also scrolling left before calling Populate();
}
void CXTPDatePickerControl::OnTimeChange()
{
CWnd::OnTimeChange();
m_dtToday = CXTPCalendarUtils::GetCurrentTime();
_RedrawControl(FALSE);
}
void CXTPDatePickerControl::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == XTP_DATEPICKER_TIMERID)
{
if (m_mouseMode == mouseScrollingLeft)
ScrollLeft(GetMonthDelta());
else if (m_mouseMode == mouseScrollingRight)
ScrollRight(GetMonthDelta());
if ((m_mouseMode == mouseTrackingHeaderList) &&
(m_pListControl != NULL))
{
m_pListControl->OnTimer(nIDEvent);
}
}
CWnd::OnTimer(nIDEvent);
}
void CXTPDatePickerControl::ShowListHeader(CRect rcHeader, COleDateTime dtMonth)
{
// make sure that the list is not already created
ASSERT(!m_pListControl);
if (m_pListControl)
{
m_pListControl->DestroyWindow();
delete m_pListControl;
m_pListControl = NULL;
}
if (!m_bIsModal)
SetCapture();
// create list
m_pListControl = new CXTPDatePickerList(this, dtMonth);
if (!m_pListControl)
throw (new CMemoryException());
// create control
m_pListControl->Create(rcHeader);
m_nTimerID = (UINT)SetTimer(XTP_DATEPICKER_TIMERID, 2 * XTP_DATEPICKER_TIMER_INTERVAL / 3, NULL);
m_mouseMode = mouseTrackingHeaderList;
}
void CXTPDatePickerControl::Select(const COleDateTime& dtDay)
{
ClearFocus();
CString s = dtDay.Format();
if (m_nMaxSelectionDays == XTP_SELECTION_INFINITE ||
m_nMaxSelectionDays > m_pSelectedDays->GetSelectedDaysCount())
{
m_pSelectedDays->Add(dtDay);
}
}
void CXTPDatePickerControl::Deselect(const COleDateTime& dtDay)
{
ClearFocus();
m_pSelectedDays->Remove(dtDay);
}
BOOL CXTPDatePickerControl::IsSelected(const COleDateTime& dtDay) const
{
BOOL bSelected = m_pSelectedDays->Contains(dtDay);
//CString s = dtDay.Format();
if (m_mouseMode == mouseSelecting ||
m_mouseMode == mouseDeselecting)
{
BOOL bBetween = FALSE;
if (m_dtFirstClicked <= m_dtLastClicked &&
m_dtFirstClicked <= dtDay && m_dtLastClicked >= dtDay)
{
bBetween = TRUE;
}
if (m_dtFirstClicked >= m_dtLastClicked &&
m_dtFirstClicked >= dtDay && m_dtLastClicked <= dtDay)
{
bBetween = TRUE;
}
if (bBetween && m_mouseMode == mouseSelecting)
{
COleDateTimeSpan spDays = dtDay - m_dtFirstClicked;
int nDays = abs(spDays.GetDays());
if (m_nMaxSelectionDays == XTP_SELECTION_INFINITE ||
m_pSelectedDays->GetSelectedDaysCount() + nDays < m_nMaxSelectionDays)
{
bSelected = TRUE;
}
}
if (bBetween && m_mouseMode == mouseDeselecting)
bSelected = FALSE;
}
return bSelected;
}
BOOL CXTPDatePickerControl::IsFocused(const COleDateTime& dtDay) const
{
if (m_dtFocused.GetStatus() != COleDateTime::valid)
{
return FALSE;
}
return CXTPCalendarUtils::IsEqual(CXTPCalendarUtils::ResetTime(m_dtFocused),
CXTPCalendarUtils::ResetTime(dtDay));
}
void CXTPDatePickerControl::ClearFocus()
{
CXTPSelectionHelper _selector(this);
_selector.RemoveFocus();
}
void CXTPDatePickerControl::OnButtonClick(UINT nID)
{
XTP_NC_DATEPICKER_BUTTON nm;
nm.nID = nID;
SendNotification(XTP_NC_DATEPICKERBUTTONCLICKED, nID);
SendMessageToParent(XTP_NC_DATEPICKER_BUTTON_CLICK, (NMHDR*)&nm);
switch (nID)
{
case XTP_IDS_DATEPICKER_TODAY:
{
// behavior: change selection to today
ClearFocus();
m_pSelectedDays->Clear();
COleDateTime dt;
GetToday(dt);
EnsureVisible(dt);
Select(dt);
SendNotification(XTP_NC_DATEPICKERSELECTIONCHANGED);
SendMessageToParent(XTP_NC_DATEPICKER_SELECTION_CHANGED);
_EndModalIfNeed();
}
break;
case XTP_IDS_DATEPICKER_NONE:
{
// behavior: change selection
ClearFocus();
m_pSelectedDays->Clear();
SendNotification(XTP_NC_DATEPICKERSELECTIONCHANGED);
SendMessageToParent(XTP_NC_DATEPICKER_SELECTION_CHANGED);
_EndModalIfNeed();
}
break;
}
}
void CXTPDatePickerControl::ProcessButtons(CPoint point)
{
for (int i = 0; i < GetButtonCount(); i++)
{
CXTPDatePickerButton* pButton = GetButton(i);
BOOL bHighlight = pButton->m_rcButton.PtInRect(point);
if (pButton == m_pButtonCaptured)
{
if (bHighlight != pButton->m_bPressed)
{
pButton->m_bPressed = bHighlight;
_RedrawControl(FALSE);
}
}
else if (pButton->m_bPressed)
{
pButton->m_bPressed = FALSE;
if (bHighlight)
OnButtonClick(pButton->m_nID);
_RedrawControl(FALSE);
}
bHighlight = pButton->m_bHighlight;
pButton->m_bHighlight = ((m_pButtonCaptured == pButton) ||
(!m_pButtonCaptured && pButton->m_rcButton.PtInRect(point)));
if (pButton->m_bHighlight != bHighlight)
{
_RedrawControl(FALSE);
}
}
}
LRESULT CXTPDatePickerControl::SendMessageToParent(int nMessage, NMHDR* pNMHDR)
{
if (!IsWindow(m_hWnd))
return 0;
NMHDR nmhdr;
if (pNMHDR == NULL)
pNMHDR = &nmhdr;
pNMHDR->hwndFrom = GetSafeHwnd();
pNMHDR->idFrom = GetDlgCtrlID();
pNMHDR->code = nMessage;
CWnd *pOwner = GetOwner();
LRESULT res = 0;
if (pOwner && IsWindow(pOwner->m_hWnd))
res = pOwner->SendMessage(WM_NOTIFY, pNMHDR->idFrom, (LPARAM)pNMHDR);
return res;
}
void CXTPDatePickerControl::_EndModalIfNeed()
{
BOOL bSingleDaySel = (GetKeyState(VK_CONTROL) < 0) || IsMultiSelectionMode();
if (m_bIsModal && !bSingleDaySel)
{
if (ContinueModal()) // skip if EndModalLoop has already called
EndModalLoop(IDOK);
}
}
void CXTPDatePickerControl::SetButtonsVisible(BOOL bShowToday, BOOL bShowNone)
{
m_arrButtons.Find(XTP_IDS_DATEPICKER_TODAY)->m_bVisible = bShowToday;
m_arrButtons.Find(XTP_IDS_DATEPICKER_NONE)->m_bVisible = bShowNone;
if (!m_rcControl.IsRectEmpty())
{
AdjustLayout(m_rcControl);
_RedrawControl(FALSE);
}
}
void CXTPDatePickerControl::EnsureVisible(const COleDateTime& dtDate)
{
int nYear = dtDate.GetYear();
int nMonth = dtDate.GetMonth();
// enumerate all month items in the collection
int nMonthCount = (int)m_arrMonths.GetSize();
for (int nIndex = 0; nIndex < nMonthCount; nIndex++)
{
CXTPDatePickerItemMonth* pMonth = m_arrMonths.GetAt(nIndex);
if (pMonth)
{
COleDateTime dtm = pMonth->GetMonth();
int iM = dtm.GetMonth();
int iY = dtm.GetYear();
if (iM == nMonth && iY == nYear)
return;
}
}
m_dtFirstMonth.SetDate(nYear, nMonth, 1);
Populate();
}
AFX_INLINE int GetEqualLeftSymbols(const CString& str1, const CString& str2)
{
int nCount = min(str1.GetLength(), str2.GetLength());
for (int i = 0; i < nCount; i++)
{
if (str1.GetAt(i) != str2.GetAt(i))
return i;
}
return nCount;
}
#ifndef LOCALE_SYEARMONTH
#define LOCALE_SYEARMONTH 0x00001006
#endif
void CXTPDatePickerControl::InitNames()
{
// initialize month names
for (int nMonth = 0; nMonth < 12; nMonth++)
{
CString strMonth = CXTPCalendarUtils::GetLocaleString(LOCALE_SMONTHNAME1 + nMonth, 255) ;
m_arMonthNames[nMonth] = strMonth;
}
int nEqualLeftSymbols = 255, nDay;
// initialize day names
for (nDay = 0; nDay < 7; nDay++)
{
CString strDayName = CXTPCalendarUtils::GetLocaleString(LOCALE_SABBREVDAYNAME1 + nDay, 255);
int nOleDayOfWeek = (nDay + 1) % 7;
m_arDayOfWeekNames[nOleDayOfWeek] = strDayName;
if (nDay > 0 && nEqualLeftSymbols > 0)
{
nEqualLeftSymbols = min(nEqualLeftSymbols, GetEqualLeftSymbols(strDayName, m_arDayOfWeekNames[1]));
}
}
// If first symbols equal, remove them.
if (nEqualLeftSymbols > 0 && !m_bRightToLeft)
{
for (nDay = 0; nDay < 7; nDay++)
m_arDayOfWeekNames[nDay].Delete(0, nEqualLeftSymbols);
}
//RTL case fix
if (m_bRightToLeft)
{
for (nDay = 0; nDay < 7; nDay++)
{
if (m_arDayOfWeekNames[nDay].Find(_T(" ")) > -1)
m_arDayOfWeekNames[nDay] = m_arDayOfWeekNames[nDay].Right(1);
else
m_arDayOfWeekNames[nDay] = m_arDayOfWeekNames[nDay].Left(1);
//if (nDay == 6) //Hebrew
// m_arDayOfWeekNames[nDay] = m_arDayOfWeekNames[nDay].Left(1);
//else
// m_arDayOfWeekNames[nDay] = m_arDayOfWeekNames[nDay].Right(1);
}
}
m_strYearMonthFormat.Empty();
if (XTPSystemVersion()->IsWin2KOrGreater())
{
m_strYearMonthFormat = CXTPCalendarUtils::GetLocaleString(LOCALE_SYEARMONTH, 256);
}
}
void CXTPDatePickerControl::SetShowNonMonthDays(BOOL bShow)
{
if (bShow != m_bShowNonMonthDays)
{
m_bShowNonMonthDays = bShow;
// set first month and last month defaults
int nMonthCount = (int)m_arrMonths.GetSize();
if (nMonthCount > 0)
{
CXTPDatePickerItemMonth* pFirstMonth = m_arrMonths.GetAt(0);
CXTPDatePickerItemMonth* pLastMonth = m_arrMonths.GetAt(nMonthCount - 1);
// by default set show previous days for first month and show following days for last month
pFirstMonth->SetShowDaysBefore(bShow);
pLastMonth->SetShowDaysAfter(bShow);
}
_RedrawControl(FALSE);
}
}
void CXTPDatePickerControl::AllowNoncontinuousSelection(BOOL bAllow /*= TRUE*/)
{
m_bAllowNoncontinuousSelection = bAllow;
if (!m_bAllowNoncontinuousSelection && m_pSelectedDays->GetSelectedBlocksCount() > 1)
{
m_pSelectedDays->Clear();
_RedrawControl(FALSE);
}
}
void CXTPDatePickerControl::SetMaxSelCount(int nMax)
{
m_nMaxSelectionDays = nMax;
int nCurrentSelectedDays = m_pSelectedDays->GetSelectedDaysCount();
// clear extra days
if (nCurrentSelectedDays > m_nMaxSelectionDays)
{
m_pSelectedDays->Clear();
_RedrawControl(FALSE);
}
}
BOOL CXTPDatePickerControl::GetSelRange(COleDateTime& refMinRange, COleDateTime& refMaxRange) const
{
return m_pSelectedDays->GetMinMaxRange(refMinRange, refMaxRange);
}
BOOL CXTPDatePickerControl::SetSelRange(const COleDateTime& dtMinRange, const COleDateTime& dtMaxRange)
{
ClearFocus();
m_pSelectedDays->SelectRange(dtMinRange, dtMaxRange);
m_dtFirstClicked = dtMinRange;
m_dtLastClicked = dtMaxRange;
return TRUE;
}
BOOL CXTPDatePickerControl::SizeMinReq(BOOL bRepaint /* = TRUE */)
{
CRect rect;
BOOL bRetVal = FALSE;
if (GetMinReqRect(rect))
{
DWORD dwFlags = SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOMOVE | SWP_NOACTIVATE;
if (!bRepaint)
dwFlags |= SWP_NOREDRAW;
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), dwFlags);
bRetVal = TRUE;
}
return bRetVal;
}
BOOL CXTPDatePickerControl::GetMinReqRect(RECT* pRect) const
{
return GetMinReqRect(pRect, 1, 1);
}
BOOL CXTPDatePickerControl::GetMinReqRect(RECT* pRect, int nRows, int nCols) const
{
CWindowDC dc(GetDesktopWindow());
CSize szMonth(m_pPaintManager->CalcMonthRect(&dc));
pRect->left = pRect->top = 0;
pRect->right = szMonth.cx * nCols;
pRect->bottom = szMonth.cy * nRows;
CRect rcBorder(0, 0, 0, 0);
m_pPaintManager->DrawBorder(0, this, rcBorder, FALSE);
pRect->right += rcBorder.left - rcBorder.right;
pRect->bottom += rcBorder.top - rcBorder.bottom;
if (m_arrButtons.GetVisibleButtonCount() > 0)
{
CSize szButton(CalcButtonSize());
pRect->bottom += szButton.cy;
}
return TRUE;
}
BOOL CXTPDatePickerControl::GetCurSel(COleDateTime& refDateTime) const
{
return m_pSelectedDays->GetMinMaxRange(refDateTime, refDateTime);
}
BOOL CXTPDatePickerControl::SetCurSel(const COleDateTime& refDateTime)
{
return SetSelRange(refDateTime, refDateTime);
}
void CXTPDatePickerControl::SetToday(const COleDateTime& refDateTime)
{
m_dtToday = refDateTime;
_RedrawControl(FALSE);
}
DWORD CXTPDatePickerControl::GetRange(COleDateTime* pMinRange, COleDateTime* pMaxRange) const
{
DWORD dwRes = 0;
if (pMinRange && m_dtMinRange.GetStatus() == COleDateTime::valid)
{
*pMinRange = m_dtMinRange;
dwRes |= GDTR_MIN;
}
if (pMaxRange && m_dtMaxRange.GetStatus() == COleDateTime::valid)
{
*pMaxRange = m_dtMaxRange;
dwRes |= GDTR_MAX;
}
return dwRes;
}
void CXTPDatePickerControl::SetDesiredVisibleAndFullRange(
COleDateTime FirstVisibleDay, COleDateTime LastVisibleDay,
COleDateTime FirstDay, COleDateTime LastDay)
{
//GetMonthRange(FirstVisibleDay, LastVisibleDay, GMR_VISIBLE);//GMR_DAYSTATE or GMR_VISIBLE
SetRange(&FirstVisibleDay, &LastVisibleDay);
m_dtMinRange = FirstDay;
m_dtMaxRange = LastDay;
}
BOOL CXTPDatePickerControl::SetRange(const COleDateTime* pMinRange, const COleDateTime* pMaxRange)
{
if (pMinRange)
{
m_dtMinRange = *pMinRange;
ScrollLeft(0);
}
if (pMaxRange)
{
m_dtMaxRange = *pMaxRange;
ScrollRight(0);
}
return TRUE;
}
int CXTPDatePickerControl::GetMonthRange(COleDateTime& refMinRange, COleDateTime& refMaxRange, DWORD dwFlags) const
{
refMinRange = m_dtFirstMonth;
refMaxRange = m_dtFirstMonth;
int nMonthCount = m_nRows * m_nColumns;
ShiftDate(refMaxRange, nMonthCount);
//if (GMR_DAYSTATE == dwFlags)
// do nothing
if (GMR_VISIBLE == dwFlags)
{
nMonthCount = (int)m_arrMonths.GetSize();
if (nMonthCount > 0)
{
CXTPDatePickerItemMonth* pLastMonth = m_arrMonths.GetAt(nMonthCount - 1);
if (pLastMonth)
{
CXTPDatePickerItemDay* pLastDay = pLastMonth->m_arrDays.GetAt(XTP_MAX_WEEKS * XTP_WEEK_DAYS - 1);
if (pLastDay->GetDate().GetMonth() != refMaxRange.GetMonth())
{
ShiftDate(refMaxRange, 1);
nMonthCount++;
}
}
CXTPDatePickerItemMonth* pFirstMonth = m_arrMonths.GetAt(0);
if (pFirstMonth)
{
CXTPDatePickerItemDay* pFirstDay = pFirstMonth->m_arrDays.GetAt(0);
if (pFirstDay->GetDate().GetMonth() != refMinRange.GetMonth())
{
ShiftDate(refMinRange, -1);
nMonthCount++;
}
}
}
}
return nMonthCount;
}
BOOL CXTPDatePickerControl::ShiftDate(COleDateTime &refDate, int nMonthCount)
{
int nYearNew = refDate.GetYear();
int nMonthNew = refDate.GetMonth();
int nInc = abs(nMonthCount) / nMonthCount;
for (int nItem = 0; nItem < abs(nMonthCount); nItem++)
{
nMonthNew += nInc;
if (nMonthNew < 1)
{
nMonthNew = 12;
nYearNew--;
}
if (nMonthNew > 12)
{
nMonthNew = 1;
nYearNew++;
}
}
return 0 == refDate.SetDate(nYearNew, nMonthNew, 1);
}
void XTPGetAsSystemTime(const COleDateTime& dateTime, SYSTEMTIME& st)
{
#if _MSC_VER < 1200
UNREFERENCED_PARAMETER(dateTime);
UNREFERENCED_PARAMETER(st);
ASSERT(FALSE);
#else
dateTime.GetAsSystemTime(st);
#endif
}
DWORD CXTPDatePickerControl::HitTest(PMCHITTESTINFO pMCHitTest) const
{
// check structure
if (!pMCHitTest)
return 0;
ASSERT(sizeof(MCHITTESTINFO) == pMCHitTest->cbSize);
// default result
pMCHitTest->uHit = MCHT_NOWHERE;
// start checking
CPoint ptHit(pMCHitTest->pt);
CXTPDatePickerItemMonth* pHitMonth = HitTest(ptHit);
if (pHitMonth)
{
CXTPDatePickerItemDay* pHitDay = pHitMonth->HitTest(ptHit);
if (pHitDay)
{
// MCHT_CALENDARDATE
pMCHitTest->uHit = MCHT_CALENDARDATE;
XTPGetAsSystemTime(pHitDay->GetDate(), pMCHitTest->st);
// MCHT_CALENDARDATEPREV
if (pHitMonth->GetShowDaysBefore() &&
pHitMonth->GetMonth().GetMonth() < pHitDay->GetDate().GetMonth())
{
pMCHitTest->uHit = MCHT_CALENDARDATEPREV;
}
else
// MCHT_CALENDARDATENEXT
if (pHitMonth->GetShowDaysAfter() &&
pHitMonth->GetMonth().GetMonth() > pHitDay->GetDate().GetMonth())
{
pMCHitTest->uHit = MCHT_CALENDARDATENEXT;
}
}
else
{
XTPGetAsSystemTime(pHitMonth->GetMonth(), pMCHitTest->st);
// MCHT_CALENDARDAY
if (pHitMonth->m_rcDaysOfWeek.PtInRect(ptHit))
{
pMCHitTest->uHit = MCHT_CALENDARDAY;
// The SYSTEMTIME structure at lpMCHitTest>st is set to the corresponding date in the top row.
CPoint ptTopRow(ptHit.x, pHitMonth->m_rcDaysOfWeek.bottom + 1);
CXTPDatePickerItemDay* pDay = pHitMonth->HitTest(ptTopRow);
if (pDay)
{
XTPGetAsSystemTime(pDay->GetDate(), pMCHitTest->st);
}
}
else
// MCHT_CALENDARWEEKNUM
if (pHitMonth->m_rcWeekNumbers.PtInRect(ptHit))
{
pMCHitTest->uHit = MCHT_CALENDARWEEKNUM;
// The SYSTEMTIME structure at lpMCHitTest>st is set to the corresponding date in the leftmost column
CPoint ptLeftRow(pHitMonth->m_rcWeekNumbers.right + 1, ptHit.y);
CXTPDatePickerItemDay* pDay = pHitMonth->HitTest(ptLeftRow);
if (pDay)
{
XTPGetAsSystemTime(pDay->GetDate(), pMCHitTest->st);
}
}
else
// MCHT_TITLEMONTH
if (pHitMonth->m_rcHeader.PtInRect(ptHit))
{
pMCHitTest->uHit = MCHT_TITLEMONTH;
}
else
// MCHT_TITLEBTNNEXT
if (pHitMonth->GetShowRightScroll() &&
pHitMonth->m_rcRightScroll.PtInRect(ptHit))
{
pMCHitTest->uHit = MCHT_TITLEBTNNEXT;
}
else
// MCHT_TITLEBTNPREV
if (pHitMonth->GetShowLeftScroll() &&
pHitMonth->m_rcLeftScroll.PtInRect(ptHit))
{
pMCHitTest->uHit = MCHT_TITLEBTNPREV;
}
}
}
else
{
// MCHT_CALENDARBK
pMCHitTest->uHit = MCHT_CALENDARBK;
}
return pMCHitTest->uHit;
}
void CXTPDatePickerControl::SetBorderStyle(XTPDatePickerBorderStyle borderStyle)
{
m_borderStyle = borderStyle;
AdjustLayout(m_rcControl);
_RedrawControl(FALSE);
}
void CXTPDatePickerControl::SetAutoSize(BOOL bAuto)
{
m_bAutoSize = bAuto;
AdjustLayout(m_rcControl);
_RedrawControl(FALSE);
}
void CXTPDatePickerControl::OnSysColorChange()
{
m_pPaintManager->RefreshMetrics();
AdjustLayout(m_rcControl);
_RedrawControl(FALSE);
}
BOOL CXTPDatePickerControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (nHitTest == HTCLIENT)
{
CPoint point;
::GetCursorPos(&point);
ScreenToClient(&point);
CXTPDatePickerItemMonth* pMonth = HitTest(point);
if (pMonth)
{
BOOL bRet = pMonth->OnSetCursor(point);
if (bRet)
return bRet;
}
}
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
void CXTPDatePickerControl::OnSetFocus(CWnd* pOldWnd)
{
CWnd::OnSetFocus(pOldWnd);
RedrawControl();
#ifdef XTP_DATEPICKER_SITENOTIFY_ONFOCUS
XTP_DATEPICKER_SITENOTIFY_ONFOCUS(this, this, TRUE)
#endif
}
void CXTPDatePickerControl::OnKillFocus (CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
RedrawControl();
#ifdef XTP_DATEPICKER_SITENOTIFY_ONFOCUS
XTP_DATEPICKER_SITENOTIFY_ONFOCUS(this, this, FALSE)
#endif
}
void CXTPDatePickerControl::OnFinalRelease()
{
CWnd::OnFinalRelease();
if (m_bDeleteOnFinalRelease)
{
CCmdTarget::OnFinalRelease();
}
}
void CXTPDatePickerControl::OnEnable(BOOL bEnable)
{
UNREFERENCED_PARAMETER(bEnable);
_RedrawControl(FALSE);
}
BOOL CXTPDatePickerControl::GetVisibleRange(COleDateTime& refFirstVisibleDay,
COleDateTime& refLastVisibleDay) const
{
int nCount = (int)m_arrMonths.GetSize();
if (!nCount || !m_arrMonths[0] || !m_arrMonths[nCount-1])
{
return FALSE;
}
if (!m_arrMonths[0]->GetDay(0))
{
ASSERT(FALSE);
return FALSE;
}
refFirstVisibleDay = m_arrMonths[0]->GetDay(0)->GetDate();
if (!m_arrMonths[0]->GetShowDaysBefore())
{
int nFirstMnDCount = m_arrMonths[0]->GetDayCount();
for (int i = 1; i < nFirstMnDCount; i++)
{
if (refFirstVisibleDay.GetMonth() == m_arrMonths[0]->GetMonth().GetMonth())
{
break;
}
refFirstVisibleDay = m_arrMonths[0]->GetDay(i)->GetDate();
}
ASSERT(refFirstVisibleDay.GetMonth() == m_arrMonths[0]->GetMonth().GetMonth());
}
int nLastMnDCount = m_arrMonths[nCount-1]->GetDayCount();
if (!nLastMnDCount || !m_arrMonths[nCount-1]->GetDay(nLastMnDCount-1))
{
ASSERT(FALSE);
return FALSE;
}
refLastVisibleDay = m_arrMonths[nCount-1]->GetDay(nLastMnDCount-1)->GetDate();
if (!m_arrMonths[nCount-1]->GetShowDaysAfter())
{
for (int i = nLastMnDCount-2; i > 0 ; i--)
{
if (refLastVisibleDay.GetMonth() == m_arrMonths[nCount-1]->GetMonth().GetMonth())
{
break;
}
refLastVisibleDay = m_arrMonths[nCount-1]->GetDay(i)->GetDate();
}
ASSERT(refLastVisibleDay.GetMonth() == m_arrMonths[nCount-1]->GetMonth().GetMonth());
}
return TRUE;
}
void CXTPDatePickerControl::EnsureVisibleSelection()
{
COleDateTime dtFirstSelDay, dtLastSelDay;
COleDateTime dtFirstVisibleDay, dtLastVisibleDay;
BOOL bRes1 = GetVisibleRange(dtFirstVisibleDay, dtLastVisibleDay);
BOOL bRes2 = GetSelRange(dtFirstSelDay, dtLastSelDay);
if (bRes1 && bRes2)
{
if (dtFirstSelDay > dtLastVisibleDay)
{
int nMonths = CXTPCalendarUtils::GetDiff_Months(dtFirstSelDay, dtLastVisibleDay);
nMonths += CXTPCalendarUtils::GetDiff_Months(dtLastSelDay, dtFirstSelDay);
nMonths = max(nMonths, 1);
ScrollRight(nMonths);
}
else if (dtLastSelDay > dtLastVisibleDay)
{
int nMonths = CXTPCalendarUtils::GetDiff_Months(dtLastSelDay, dtLastVisibleDay);
nMonths = max(nMonths, 1);
ScrollRight(nMonths);
}
//---------------------------
bRes1 = GetVisibleRange(dtFirstVisibleDay, dtLastVisibleDay);
bRes2 = GetSelRange(dtFirstSelDay, dtLastSelDay);
if (bRes1 && bRes2)
{
if (dtFirstSelDay < dtFirstVisibleDay || dtLastSelDay > dtLastVisibleDay)
{
EnsureVisible(dtLastSelDay);
EnsureVisible(dtFirstSelDay);
}
}
}
}
void CXTPDatePickerControl::SetLayoutRTL(BOOL bRightToLeft)
{
if (!XTPSystemVersion()->IsLayoutRTLSupported())
return;
m_bRightToLeft = bRightToLeft;
if (!m_hWnd)
return;
ModifyStyleEx(bRightToLeft ? 0 : WS_EX_LAYOUTRTL, !bRightToLeft ? 0 : WS_EX_LAYOUTRTL);
InitNames(); //<<>>
RedrawControl();
}
void CXTPDatePickerControl::EnsureVisibleFocus()
{
if (m_dtFocused.GetStatus() != COleDateTime::valid)
{
return;
}
COleDateTime dtFirstVisibleDay, dtLastVisibleDay;
BOOL bRes1 = GetVisibleRange(dtFirstVisibleDay, dtLastVisibleDay);
if (bRes1)
{
if (m_dtFocused > dtLastVisibleDay)
{
int nMonths = CXTPCalendarUtils::GetDiff_Months(m_dtFocused, dtLastVisibleDay);
nMonths = max(nMonths, 1);
ScrollRight(nMonths);
m_dtFocused.SetStatus(COleDateTime::valid);
}
//---------------------------
bRes1 = GetVisibleRange(dtFirstVisibleDay, dtLastVisibleDay);
if (bRes1)
{
if (m_dtFocused < dtFirstVisibleDay || m_dtFocused > dtLastVisibleDay)
{
EnsureVisible(m_dtFocused);
}
}
}
}
XTPCalendarTheme CXTPDatePickerControl::GetPaintTheme() const
{
if (m_pPaintManager)
return m_pPaintManager->GetPaintTheme();
return xtpCalendarThemeUnknown;
}
void CXTPDatePickerControl::SetPaintTheme(XTPCalendarTheme ePaintTheme)
{
if (ePaintTheme == xtpCalendarThemeResource)
{
SetTheme(new CXTPDatePickerThemeOffice2007());
}
else
{
SetTheme(new CXTPDatePickerPaintManager());
}
if (m_pPaintManager)
{
m_pPaintManager->SetPaintTheme(ePaintTheme);
}
}
/////////////////////////////////////////////////////////////////////////////
//class CXTPSelectionHelper
CXTPDatePickerControl::CXTPSelectionHelper::CXTPSelectionHelper(CXTPDatePickerControl* pControl)
{
ASSERT(pControl);
m_pDP = pControl;
}
void CXTPDatePickerControl::CXTPSelectionHelper::InitFocusIfNeed()
{
if (m_pDP->m_dtFocused.GetStatus() != COleDateTime::valid)
{
COleDateTime dtSel0, dtSel1;
BOOL bSelExists = m_pDP->GetSelectedDays()->GetMinMaxRange(dtSel0, dtSel1);
if (!bSelExists)
{
dtSel0.SetDate(m_pDP->m_dtFirstMonth.GetYear(), m_pDP->m_dtFirstMonth.GetMonth(), 1);
}
m_pDP->m_dtFocused = dtSel0;
if (m_pDP->m_dtFirstClicked.GetStatus() == COleDateTime::valid &&
m_pDP->m_dtFirstClicked >= dtSel0 && m_pDP->m_dtFirstClicked <= dtSel1)
{
m_pDP->m_dtFSelBase = m_pDP->m_dtFirstClicked;
}
else
{
m_pDP->m_dtFSelBase = dtSel0;
}
}
}
void CXTPDatePickerControl::CXTPSelectionHelper::RemoveFocus()
{
m_pDP->m_dtFocused.SetStatus(COleDateTime::null);
m_pDP->m_dtFSelBase.SetStatus(COleDateTime::null);
}
void CXTPDatePickerControl::CXTPSelectionHelper::_TmpSaveFocus()
{
m_dtFocusedTmp = m_pDP->m_dtFocused;
m_dtFSelBaseTmp = m_pDP->m_dtFSelBase;
}
void CXTPDatePickerControl::CXTPSelectionHelper::_TmpRestoreFocus()
{
m_pDP->m_dtFocused = m_dtFocusedTmp;
m_pDP->m_dtFSelBase = m_dtFSelBaseTmp;
}
void CXTPDatePickerControl::CXTPSelectionHelper::MoveFocus(int eStep, int eDirection,
BOOL bContinuouse, BOOL bSaveSel)
{
ASSERT(eDirection == 1 || eDirection == -1);
if (bContinuouse)
{
bSaveSel = FALSE;
}
InitFocusIfNeed();
_MoveFocus(eStep, eDirection);
if (bContinuouse)
{
COleDateTime dtSel0 = m_pDP->m_dtFocused;
COleDateTime dtSel1 = m_pDP->m_dtFSelBase;
BOOL bBackSel = dtSel0 > dtSel1;
if (bBackSel)
{
dtSel1 = m_pDP->m_dtFocused;
dtSel0 = m_pDP->m_dtFSelBase;
}
int nDays = (int)dtSel1 - (int)dtSel0;
int nMaxSel = m_pDP->GetMaxSelCount();
if (nMaxSel == XTP_SELECTION_INFINITE)
{
nMaxSel = INT_MAX;
}
if (nDays > nMaxSel)
{
if (bBackSel)
{
dtSel1 = (double)dtSel0 + nMaxSel;
}
else
{
dtSel0 = (double)dtSel1 - nMaxSel;
}
}
m_pDP->GetSelectedDays()->Clear();
m_pDP->GetSelectedDays()->SelectRange(dtSel0, dtSel1);
}
else
{
//int nSelDays = m_pDP->GetSelectedDays()->GetSelectedDaysCount();
if (!bSaveSel)
{
m_pDP->GetSelectedDays()->Clear();
}
if (!bSaveSel /*|| nSelDays == 0*/)
{
m_pDP->GetSelectedDays()->Add(m_pDP->m_dtFocused);
}
m_pDP->m_dtFSelBase = m_pDP->m_dtFocused;
}
}
void CXTPDatePickerControl::CXTPSelectionHelper::SelUnselFocus()
{
InitFocusIfNeed();
BOOL bSelected = m_pDP->GetSelectedDays()->Contains(m_pDP->m_dtFocused);
if (bSelected)
{
m_pDP->GetSelectedDays()->Remove(m_pDP->m_dtFocused);
}
else
{
int nSelDays = m_pDP->GetSelectedDays()->GetSelectedDaysCount();
int nMaxSel = m_pDP->GetMaxSelCount();
if (nMaxSel == XTP_SELECTION_INFINITE)
{
nMaxSel = INT_MAX;
}
if (nSelDays < nMaxSel)
{
m_pDP->GetSelectedDays()->Add(m_pDP->m_dtFocused);
}
}
}
void CXTPDatePickerControl::CXTPSelectionHelper::_MoveFocus(int eStep, int eDirection)
{
ASSERT(eDirection == 1 || eDirection == -1);
InitFocusIfNeed();
COleDateTime dtNew = m_pDP->m_dtFocused;
if (eStep == stepDay || eStep == stepWeek)
{
dtNew = (double)dtNew + eDirection * (eStep == stepDay ? 1 : 7);
}
else if (eStep == stepMonth || eStep == stepYear)
{
int nMonths = eDirection * (eStep == stepMonth ? 1 : 12);
CXTPCalendarUtils::ShiftDate_Month(dtNew, nMonths, dtNew.GetDay());
}
else if (eStep == stepWeekBE)
{
int nFWD = m_pDP->GetFirstDayOfWeek();
int nShift = -1 * ((dtNew.GetDayOfWeek() - nFWD + 7) % 7);
if (eDirection == dirNext)
{
nShift += 6;
}
dtNew = (double)dtNew + nShift;
}
else if (eStep == stepMonthBE)
{
CXTPCalendarUtils::UpdateMonthDay(dtNew, eDirection == dirPrev ? 1 : 31);
}
else
{
ASSERT(FALSE);
}
m_pDP->m_dtFocused = dtNew;
}
void CXTPDatePickerControl::SendNotification(XTP_NOTIFY_CODE EventCode, WPARAM wParam, LPARAM lParam)
{
m_pConnection->SendEvent(EventCode, wParam, lParam);
}