#include "stdafx.h"
#include <QtGui/QPaintEvent>
#include "DrawDateTime.h"
#define STR(a) QStringLiteral(a)
enum { Y_PRE = 6 * 7, Y_NEXT, M_PRE, M_NEXT };
namespace
{
//指定月份有多少天
unsigned short DayofMonth(int year, int month)
{
int day = 31;
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
day = 31;
break;
case 2:
{
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
{
day = 29;
}
else
{
day = 28;
}
}
break;
case 4:
case 6:
case 9:
case 11:
day = 30;
break;
}
return day;
}
int CalDayofWeek(int year, int month, int day)//计算指定月份1号为周几
{
//W = [C/4] - 2C + y + [y/4] + [13 * (M+1) / 5] + d - 1
//C:世纪(前两位) y:年(后两位) m:月 大于3小于14 d日
if (month <= 2)
{
month += 12;
year -= 1;
}
int c = year / 100;
int y = year % 100;
int w = (c / 4 - 2 * c + y + y / 4 + 13 * (month + 1) / 5 + day - 1 + 7) % 7;
return w;
}
};
struct tDayFlag
{
signed char m_chFlagM; // -1 pre 0 cur 1 next
unsigned short m_chFlagD; // day num
};
struct DrawDateTime::DrawDateTimePrivate
{
public:
DrawDateTimePrivate(DrawDateTime * s)
: m_Self(s)
//, m_pOnChanged(NULL)
{
m_aRect = new QRect[m_column_count * m_row_count];
m_aDayFlag = new tDayFlag[m_column_count * m_row_count];
m_sOverIndex = -1;
SYSTEMTIME st;
GetLocalTime(&st);
m_wYear = st.wYear;
m_wMonth = st.wMonth;
m_wDay = st.wDay;
}
~DrawDateTimePrivate()
{
delete []m_aRect;
delete []m_aDayFlag;
}
public:
unsigned int GetColumnLeft(int column)
{
unsigned int left = (width - leftBorder - rightBorder + columnSpace) / m_column_count * column + leftBorder;
return left;
}
unsigned int GetColumnRight(int column)
{
if (column < 0 || column > m_column_count)
{
column = 0;
}
//总宽度-左border-由border-(m_column_count-1)*列间隙
unsigned int itemWidth = (width - leftBorder - rightBorder - (m_column_count - 1) * columnSpace) / m_column_count;
unsigned int right = GetColumnLeft(column) + itemWidth;
return right;
}
unsigned int GetRowTop(int row)
{
QFontMetrics fm(weekFont);
int weekHeight = fm.height();
unsigned int top = (height - topBorder - bottomBorder - weekHeight + rowSpace) / m_row_count * row
+ space + weekHeight;
return top;
}
unsigned int GetRowBottom(int row)
{
if (row < 0 || row > m_row_count)
{
row = 0;
}
QFontMetrics fm(weekFont);
int weekHeight = fm.height();
//总高度-上border-下border-(m_row_count-1)*行间隙-week高
unsigned int itemHeight = (height - topBorder - bottomBorder - weekHeight - space - (m_row_count - 1) * rowSpace) / m_row_count;
unsigned int bottom = GetRowTop(row) + itemHeight;
return bottom;
}
public:
int columnSpace = 5;
int rowSpace = 5;
int leftBorder = 10;
int rightBorder = 10;
int topBorder = 5;
int bottomBorder = 5;
int width = 100;
int height = 80;
int space = 10;//周名称和天之间距离
int m_column_count = 7;//列数
int m_row_count = 6;//行数
QFont weekFont = QFont(STR("微软雅黑"), 10);
QFont dayFont;
public:
DrawDateTime * m_Self;
//选中天
unsigned short m_wYear;
unsigned short m_wMonth;
unsigned short m_wDay;
//计算日历位置
unsigned short m_sYear;
unsigned short m_sMonth;
unsigned short m_sDay;
tDayFlag * m_aDayFlag; // 各个按钮日期号
QRect * m_aRect; // 各个按钮区域
short m_sOverIndex; // 热点按钮下标
bool MatchRealDate(tDayFlag df)
{
if (df.m_chFlagD == m_wDay && m_sMonth == m_wMonth)
{
return true;
}
return false;
}
bool MatchSelectedDate(tDayFlag df)
{
if (df.m_chFlagD == m_sMonth && 0 == df.m_chFlagM)
{
return true;
}
return false;
}
//重置当前月份上的日期flag及显示的数据
void ResetDayFlag()
{
unsigned short preY, preM;
GetPreviousMonth(preY, preM);
int nPreMonDays = DayofMonth(preY, preM);
int nCurMonDays = DayofMonth(m_sYear, m_sMonth);
int week = CalDayofWeek(m_sYear, m_sMonth, 1);
int index = 0;
for (int i = 0; i < week; ++i, index++)
{
m_aDayFlag[index].m_chFlagM = -1;
m_aDayFlag[index].m_chFlagD = (nPreMonDays - week + 1) + i;
}
for (int i = 0; i < nCurMonDays; ++i, index++)
{
m_aDayFlag[index].m_chFlagM = 0;
m_aDayFlag[index].m_chFlagD = i + 1;
}
m_row_count = index / 7 + (index % 7 == 0 ? 0 : 1);
for (int j = 1; index < m_column_count * m_row_count; ++j, ++index)
{
m_aDayFlag[index].m_chFlagM = 1;
m_aDayFlag[index].m_chFlagD = j;
}
}
//获取上一个月的年和月份
void GetPreviousMonth(unsigned short & preYear, unsigned short & preMonth)
{
if (m_sMonth > 1)
{
preYear = m_sYear;
preMonth = m_sMonth - 1;
}
else
{
preYear = m_sYear - 1;
preMonth = 12;
}
}
//获取下一个月的年和月份
void GetNextMonth(unsigned short & nextYear, unsigned short & nextMonth)
{
if (m_sMonth >= 12)
{
nextYear = m_sYear + 1;
nextMonth = 1;
}
else
{
nextYear = m_sYear;
nextMonth = m_sMonth + 1;
}
}
};
DrawDateTime::DrawDateTime(QWidget *parent)
: QWidget(parent)
, d_ptr(new DrawDateTimePrivate(this))
{
setMouseTracking(true);
}
DrawDateTime::~DrawDateTime()
{
}
void DrawDateTime::SetDate(unsigned short year, unsigned short month, unsigned short day)
{
d_ptr->m_sYear = year;
d_ptr->m_sMonth = month;
d_ptr->m_sDay = day;
update();
}
void DrawDateTime::GetDate(unsigned short & year, unsigned short & month, unsigned short & day)
{
year = d_ptr->m_sYear;
month = d_ptr->m_sMonth;
day = d_ptr->m_sDay;
}
void DrawDateTime::PreviousMonth()
{
unsigned short year, month;
d_ptr->GetPreviousMonth(year, month);
int acturlDays = DayofMonth(year, month);
if (acturlDays < d_ptr->m_wDay)
{
d_ptr->m_sDay = acturlDays;
}
SetDate(year, month, d_ptr->m_sDay);
update();
}
void DrawDateTime::NextMonth()
{
unsigned short year, month;
d_ptr->GetNextMonth(year, month);
int acturlDays = DayofMonth(year, month);
if (acturlDays < d_ptr->m_wDay)
{
d_ptr->m_wDay = acturlDays;
}
SetDate(year, month, d_ptr->m_wDay);
update();
}
void DrawDateTime::paintEvent(QPaintEvent * event)
{
QPainter painter(this);
painter.drawRect(rect().adjusted(1, 1, -1, -1));
painter.fillRect(rect().adjusted(1, 1, -1, -1), Qt::gray);
DrawWeek(painter);
//painter.translate(rect().center());
//painter.rotate(90);
//painter.translate(-rect().center());
// painter.setRenderHint(QPainter::Antialiasing);
DrawDay(painter);
}
void DrawDateTime::resizeEvent(QResizeEvent * event)
{
d_ptr->width = event->size().width();
d_ptr->height = event->size().height();
}
void DrawDateTime::mouseMoveEvent(QMouseEvent * event)
{
int cur = GetIndex(event->pos());
bool b = (cur != d_ptr->m_sOverIndex);
if (b)
{
int previousHover = d_ptr->m_sOverIndex;
d_ptr->m_sOverIndex = cur;
update(d_ptr->m_aRect[cur]);
update(d_ptr->m_aRect[previousHover]);
}
QWidget::mouseMoveEvent(event);
}
void DrawDateTime::mousePressEvent(QMouseEvent * event)
{
if (event->button() == Qt::LeftButton)
{
int cur = GetIndex(event->pos());
if (cur == -1)
{
return;
}
tDayFlag & flag = d_ptr->m_aDayFlag[cur];
unsigned short year = d_ptr->m_sYear, month = d_ptr->m_sMonth;
if (flag.m_chFlagM == -1)
{
d_ptr->GetPreviousMonth(year, month);
}
else if (flag.m_chFlagM == 1)
{
d_ptr->GetNextMonth(year, month);
}
bool b = (d_ptr->m_wDay != flag.m_chFlagD || month != d_ptr->m_wMonth || year != d_ptr->m_wYear);
if (b)
{
d_ptr->m_wDay = flag.m_chFlagD