⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 minicalendarctrl.cpp

📁 一款最完整的工业组态软源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// ----------------------------------------------------------------------------
// Written by Tony Ioanides (tonyi@bigpond.com)
// Copyright (c) 2003 Tony Ioanides.
//
// This code may be used in compiled form in any way you desire. This file may 
// be redistributed by any means PROVIDING it is not sold for profit without 
// the authors written consent, and providing that this notice and the authors 
// name is included. 
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to you or your
// computer whatsoever.
// ----------------------------------------------------------------------------

#include "stdafx.h"
#include "MiniCalendarCtrl.h"

#include <algorithm>

#ifndef NUM_ELEMENTS
	#define NUM_ELEMENTS(a) (sizeof(a)/sizeof(*a))
#endif // NUM_ELEMENTS

// ----------------------------------------------------------------------------
static CRect
MC_GetArrowRect(CRect rectHeader, BOOL bLeftArrow)
{
	const int yMid = (rectHeader.top + rectHeader.bottom) / 2;
	const int cx = rectHeader.Height() / 5;

	rectHeader.top = yMid - cx;
	rectHeader.bottom = yMid + cx;

	if (bLeftArrow)
	{
		rectHeader.left += 6;
		rectHeader.right = rectHeader.left + cx;
	}
	else
	{
		rectHeader.right -= 6;
		rectHeader.left = rectHeader.right - cx;
	}

	return rectHeader;
}

// ----------------------------------------------------------------------------
static void
MC_DrawArrow(CDCHandle dc, CRect rectHeader, BOOL bLeftArrow)
{
	RECT rect = MC_GetArrowRect(rectHeader, bLeftArrow);

	if (bLeftArrow)
		std::swap(rect.left, rect.right);

	POINT ptTriangle[] = 
	{
		{ rect.left, rect.top },
		{ rect.left, rect.bottom },
		{ rect.right, (rect.top + rect.bottom) / 2 }
	};

	HBRUSH hbrOrig = dc.SelectStockBrush(BLACK_BRUSH);

	dc.Polygon(ptTriangle, NUM_ELEMENTS(ptTriangle));
	dc.SelectBrush(hbrOrig);
}

// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
// Internal constants

enum
{
	nMonthsPerYear = 12,
	nDaysPerWeek = 7,
	nRowsPerCell = 6,
	nDaysPerCell = nRowsPerCell * nDaysPerWeek,
	nBorderSize = 4,
	nCellMargin = 10
};

#define ID_TIMER_FIRST  0xDEAD
#define ID_TIMER_REPEAT 0xC0DE

#define HEADER_FORMAT   _T("%B %Y")

// ----------------------------------------------------------------------------
CMiniCalendarCtrl::CMiniCalendarCtrl()
{
	m_crBack = GetSysColor(COLOR_WINDOW);

	m_bShow3dBorder = 1;
	m_bShowNonMonthDays = 1;
	m_bHighlightToday = 1;
	m_bMultiSelEnabled = 1;

	m_nCols = 1;
	m_nRows = 1;

	m_nFirstDayOfWeek = 1;
	m_nStartMonth = 1;
	m_nStartYear = 1970;
	m_nMonthsToScroll = 1;

	m_daySpace.cx = 4;
	m_daySpace.cy = 4;

	m_nActiveElement = 0;
}

// ----------------------------------------------------------------------------
BOOL
CMiniCalendarCtrl::IsDateSelected(const COleDateTime& date) const
{
	if (m_dtSelect.GetStatus() != COleDateTime::valid)
		return FALSE;

	if (date == m_dtSelect)
		return TRUE;
		
	if (m_bMultiSelEnabled && m_dtAnchor.GetStatus() == COleDateTime::valid)
		return m_dtSelect > m_dtAnchor ?
			(date >= m_dtAnchor && date <= m_dtSelect) :
			(date >= m_dtSelect && date <= m_dtAnchor);

	return FALSE;
}

// ----------------------------------------------------------------------------
SIZE
CMiniCalendarCtrl::GetMaxSize() const
{
	return GetMaxSize(m_nCols, m_nRows);
}

// ----------------------------------------------------------------------------
SIZE
CMiniCalendarCtrl::GetMaxSize(UINT nCols, UINT nRows) const
{
	const int cxyBorder = m_bShow3dBorder ? (nBorderSize * 2) : 0;

	return CSize(
		nCols * m_cellSize.cx + cxyBorder,
		nRows * m_cellSize.cy + cxyBorder);
}

// ----------------------------------------------------------------------------
BOOL 
CMiniCalendarCtrl::SetLayout(UINT nCols, UINT nRows)
{
	if (nCols > 0 && nRows > 0 && ((int) nCols != m_nCols || (int) nRows != m_nRows))
	{
		m_nCols = nCols; 
		m_nRows = nRows;

		AutoSize();
		return TRUE;
	}

	return FALSE;
}

// ----------------------------------------------------------------------------
BOOL
CMiniCalendarCtrl::SetFirstDayOfWeek(UINT nFirstDayOfWeek)
{
	if (nFirstDayOfWeek >= 1 && nFirstDayOfWeek <= nDaysPerWeek &&
		nFirstDayOfWeek != (UINT) m_nFirstDayOfWeek)
	{
		m_nFirstDayOfWeek = nFirstDayOfWeek;
		Invalidate();
		return TRUE;
	}

	return FALSE;
}

// ----------------------------------------------------------------------------
void
CMiniCalendarCtrl::AutoSize()
{
	const SIZE size = GetMaxSize();
	SetWindowPos(0, 0, 0, size.cx, size.cy, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}

// ----------------------------------------------------------------------------
BOOL
CMiniCalendarCtrl::EnsureVisible(const COleDateTime& date)
{
	if (date.GetStatus() != COleDateTime::valid)
		return FALSE;

	if (date >= GetMonthFromCell(0, 0) &&
		date <= GetMonthFromCell(m_nCols - 1, m_nRows - 1))
		return FALSE;

	m_nStartMonth = date.GetMonth();
	m_nStartYear = date.GetYear();

	RedrawWindow();
	return TRUE;
}

// ----------------------------------------------------------------------------
BOOL
CMiniCalendarCtrl::ResetRange()
{
	if (m_dtAnchor.GetStatus() == COleDateTime::valid)
	{
		m_dtAnchor.SetStatus(COleDateTime::invalid);
		NotifySelChanged();

		Invalidate();
		return TRUE;
	}
	
	m_dtAnchor.SetStatus(COleDateTime::invalid);
	return FALSE;
}

// ----------------------------------------------------------------------------
LRESULT
CMiniCalendarCtrl::OnCreate(LPCREATESTRUCT lpcs) 
{
	hNotifyWindow = GetParent();

	m_font[FontHeader].bBold = TRUE;
	m_font[FontHeader].nFontSize = 10;

	m_font[FontSpecialDayNumber].bBold = TRUE;

	for (int i = 0; i < NUM_ELEMENTS(m_font); ++i)
		CreateFont(i);

	ApplyStyle(lpcs->style);
	
	RecalcLayout();
	AutoSize();
	EnsureVisible(COleDateTime::GetCurrentTime());

	SetMsgHandled(FALSE);
	return 0;
}

// ----------------------------------------------------------------------------
LRESULT
CMiniCalendarCtrl::OnStyleChanged(UINT nType, LPSTYLESTRUCT lpss)
{
	if (nType & GWL_STYLE)
		ApplyStyle(lpss->styleNew);

	SetMsgHandled(FALSE);
	return 0;
}

// ----------------------------------------------------------------------------
LRESULT 
CMiniCalendarCtrl::OnTimer(UINT nID, TIMERPROC /*fnProc*/)
{
	switch (nID)
	{
		case ID_TIMER_FIRST:
			KillTimer(ID_TIMER_FIRST);
			if (m_nActiveElement & htHeader)
			{
				DoScroll(m_nActiveElement, m_nMonthsToScroll);

				int nElapse = 250;
				DWORD nRepeat = 40;

				if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0))
					nElapse = 10000 / (5 * nRepeat + 25);	// milli-seconds, approximated
				SetTimer(ID_TIMER_REPEAT, nElapse);
			}
			break;

		case ID_TIMER_REPEAT:
			if (m_nActiveElement & htHeader)
				DoScroll(m_nActiveElement, m_nMonthsToScroll);
			else if (GetCapture() != m_hWnd)
				KillTimer(ID_TIMER_REPEAT);
			break;

		default:
			break;
	}

	return 0;
}

// ----------------------------------------------------------------------------
LRESULT
CMiniCalendarCtrl::OnMouseMove(UINT /*nFlags*/, CPoint point) 
{
	if (GetCapture() == m_hWnd)
	{
		m_nActiveElement &= ~htHeader;

		HitTestInfo ht;
		ht.ptHit = point;

		if (HitTest(ht))
		{
			if ((m_nActiveElement & htDate) && (ht.nFlags & htDate) && ht.dtHit != m_dtSelect)
			{
				m_dtSelect = ht.dtHit;

				if (ht.nFlags & (htBack | htNext))
					DoScroll(ht.nFlags);
				else
					RedrawWindow();

				NotifySelChanged();
			}

			if ((m_nActiveElement & (htBack | htNext)) &&
				ht.nFlags == UINT(htHeader | m_nActiveElement))
			{
				ATLTRACE("ResumeScroll\n");
				m_nActiveElement = ht.nFlags;
			}
		}
	}

	return 0;
}

// ----------------------------------------------------------------------------
LRESULT
CMiniCalendarCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	m_nActiveElement = 0;

	HitTestInfo ht;
	ht.ptHit = point;

	if (HitTest(ht)) 
	{
		SetCapture();
		m_nActiveElement = ht.nFlags;

		if (m_nActiveElement & htHeader)
		{
			if (m_nActiveElement & (htBack | htNext))
			{
				DoScroll(ht.nFlags, m_nMonthsToScroll);

				int nElapse = 250;
				int nDelay = 0;
				if (SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0))
					nElapse += nDelay * 250;	// all milli-seconds
				SetTimer(ID_TIMER_FIRST, nElapse);
			}
			else
			{
				// Show month list here.
			}
		}
		else if (m_nActiveElement & htButton)
		{
		}
		else if (m_nActiveElement & htDate)
		{
			if (m_dtAnchor.GetStatus() != COleDateTime::valid || ! (nFlags & MK_SHIFT))
				m_dtAnchor = ht.dtHit;

			m_dtSelect = ht.dtHit;

			if (m_nActiveElement & (htBack | htNext))
				DoScroll(ht.nFlags);
			else
				RedrawWindow();

			NotifySelChanged();
		}
		else
			ResetRange();
	}

	return 0;
}

// ----------------------------------------------------------------------------
LRESULT
CMiniCalendarCtrl::OnLButtonUp(UINT /*nFlags*/, CPoint /*point*/) 
{
	ReleaseCapture();
	m_nActiveElement = 0;
	return 0;
}

// ----------------------------------------------------------------------------
LRESULT
CMiniCalendarCtrl::OnCaptureChanged(HWND /*hWnd*/) 
{
	m_nActiveElement = 0;
	return 0;
}

// ----------------------------------------------------------------------------
void
CMiniCalendarCtrl::DrawBorder(CDCHandle dc, CRect& rectClient)
{
	if (m_bShow3dBorder)
	{
		static const struct
		{
			COLORREF crTL;
			COLORREF crBR;
		} border[] =
		{
			{ COLOR_3DFACE,    COLOR_BTNTEXT },
			{ COLOR_3DHILIGHT, COLOR_3DSHADOW },
			{ COLOR_3DFACE,    COLOR_3DFACE },
			{ COLOR_3DSHADOW,  COLOR_3DHILIGHT }
		};

		for (int i = 0; i < NUM_ELEMENTS(border); ++i)
		{
			dc.Draw3dRect(rectClient, 
				GetSysColor(border[i].crTL), 
				GetSysColor(border[i].crBR));
			rectClient.DeflateRect(1, 1);
		}
	}
}

// ----------------------------------------------------------------------------
int
CMiniCalendarCtrl::DrawHeader(CDCHandle dc, CPoint pt, int nCol, int nRow)
{
	CRect rectHeader(0, 0, m_cellSize.cx, m_cyHeader);
	rectHeader.OffsetRect(pt);

	// Draw 'button' part
	dc.Draw3dRect(rectHeader, 
		GetSysColor(COLOR_3DHILIGHT), GetSysColor(COLOR_3DSHADOW));
	rectHeader.DeflateRect(1, 1);

	dc.FillSolidRect(rectHeader, GetSysColor(COLOR_3DFACE));
	rectHeader.DeflateRect(1, 1);

	// Draw the text
	const COleDateTime dt = GetMonthFromCell(nCol, nRow);
	const CString str = dt.Format(HEADER_FORMAT);

	SelectFont(dc, FontHeader);

	dc.DrawText(str, str.GetLength(), rectHeader, 
		DT_CENTER | DT_VCENTER | DT_SINGLELINE);

	// Draw arrow(s) (if required)
	if (nRow == 0 && (nCol == 0 || nCol == m_nCols - 1))
	{
		rectHeader.SetRect(0, 0, m_cellSize.cx, m_cyHeader);
		rectHeader.OffsetRect(pt);

		if (nCol == 0)
			MC_DrawArrow(dc, rectHeader, TRUE);

		if (nCol == m_nCols - 1)
			MC_DrawArrow(dc, rectHeader, FALSE);
	}

	return m_cyHeader;
}

// ----------------------------------------------------------------------------
int 
CMiniCalendarCtrl::DrawDaysOfWeek(CDCHandle dc, CPoint pt, int /*nCol*/, int /*nRow*/)
{
	const int cxColumn = m_dateSize.cx + m_daySpace.cx;
	const int xBeg = pt.x + m_xCol;

	SelectFont(dc, FontDayName);

	// Draw day names.
	CRect rectDate(xBeg, pt.y, xBeg + cxColumn, pt.y + m_cyDayNames);

	for (int i = 1; i <= nDaysPerWeek; ++i)
	{
		dc.DrawText(GetDayOfWeekName(i), 1, rectDate,  
			DT_SINGLELINE | DT_RIGHT | DT_VCENTER);
		rectDate.OffsetRect(cxColumn, 0);
	}
	rectDate.bottom += 4;

	// Draw separator.
	dc.SelectBrush(GetSysColorBrush(COLOR_3DSHADOW));
	dc.PatBlt(xBeg, rectDate.bottom - 2, 
		cxColumn * nDaysPerWeek + m_daySpace.cx, 1, PATCOPY);

	return rectDate.bottom - pt.y;
}

// ----------------------------------------------------------------------------
int 
CMiniCalendarCtrl::DrawDays(CDCHandle dc, CPoint pt, int nCol, int nRow)
{
	const int cxColumn = m_dateSize.cx + m_daySpace.cx;
	const int xBeg = pt.x + m_xCol;

	COleDateTime dt = GetFirstDayInCell(nCol, nRow);

	const COleDateTime dtCell = GetMonthFromCell(nCol, nRow);
	const COleDateTime dtToday = COleDateTime::GetCurrentTime();

	const BOOL bBegRange = nCol == 0 && nRow == 0;
	const BOOL bEndRange = nCol == m_nCols - 1 && nRow == m_nRows - 1;
	const int nThisMonth = dtCell.GetMonth();

	// Determine position of 'today' in this cell (if required).
	CPoint ptToday(-1, -1);

	if (m_bHighlightToday && 
		dtToday.GetMonth() == nThisMonth &&	dtToday.GetYear() == dtCell.GetYear())
	{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -