calctrl.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,791 行 · 第 1/4 页
CPP
1,791 行
if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
{
// draw the sequential month-selector
dc.SetBackgroundMode(wxTRANSPARENT);
dc.SetTextForeground(*wxBLACK);
dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID));
dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID));
dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow);
// Get extent of month-name + year
wxCoord monthw, monthh;
wxString headertext = m_date.Format(wxT("%B %Y"));
dc.GetTextExtent(headertext, &monthw, &monthh);
// draw month-name centered above weekdays
wxCoord monthx = ((m_widthCol * 7) - monthw) / 2 + x0;
wxCoord monthy = ((m_heightRow - monthh) / 2) + y;
dc.DrawText(headertext, monthx, monthy);
// calculate the "month-arrows"
wxPoint leftarrow[3];
wxPoint rightarrow[3];
int arrowheight = monthh / 2;
leftarrow[0] = wxPoint(0, arrowheight / 2);
leftarrow[1] = wxPoint(arrowheight / 2, 0);
leftarrow[2] = wxPoint(arrowheight / 2, arrowheight - 1);
rightarrow[0] = wxPoint(0,0);
rightarrow[1] = wxPoint(arrowheight / 2, arrowheight / 2);
rightarrow[2] = wxPoint(0, arrowheight - 1);
// draw the "month-arrows"
wxCoord arrowy = (m_heightRow - arrowheight) / 2;
wxCoord larrowx = (m_widthCol - (arrowheight / 2)) / 2 + x0;
wxCoord rarrowx = ((m_widthCol - (arrowheight / 2)) / 2) + m_widthCol*6 + x0;
m_leftArrowRect = m_rightArrowRect = wxRect(0,0,0,0);
if ( AllowMonthChange() )
{
wxDateTime ldpm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) - wxDateSpan::Day(); // last day prev month
// Check if range permits change
if ( IsDateInRange(ldpm) && ( ( ldpm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) )
{
m_leftArrowRect = wxRect(larrowx - 3, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6));
dc.SetBrush(*wxBLACK_BRUSH);
dc.SetPen(*wxBLACK_PEN);
dc.DrawPolygon(3, leftarrow, larrowx , arrowy, wxWINDING_RULE);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(m_leftArrowRect);
}
wxDateTime fdnm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) + wxDateSpan::Month(); // first day next month
if ( IsDateInRange(fdnm) && ( ( fdnm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) )
{
m_rightArrowRect = wxRect(rarrowx - 4, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6));
dc.SetBrush(*wxBLACK_BRUSH);
dc.SetPen(*wxBLACK_PEN);
dc.DrawPolygon(3, rightarrow, rarrowx , arrowy, wxWINDING_RULE);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(m_rightArrowRect);
}
}
y += m_heightRow;
}
// first draw the week days
if ( IsExposed(x0, y, x0 + 7*m_widthCol, m_heightRow) )
{
#if DEBUG_PAINT
wxLogDebug("painting the header");
#endif
dc.SetBackgroundMode(wxTRANSPARENT);
dc.SetTextForeground(m_colHeaderFg);
dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID));
dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID));
dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow);
bool startOnMonday = (GetWindowStyle() & wxCAL_MONDAY_FIRST) != 0;
for ( int wd = 0; wd < 7; wd++ )
{
size_t n;
if ( startOnMonday )
n = wd == 6 ? 0 : wd + 1;
else
n = wd;
wxCoord dayw, dayh;
dc.GetTextExtent(m_weekdays[n], &dayw, &dayh);
dc.DrawText(m_weekdays[n], x0 + (wd*m_widthCol) + ((m_widthCol- dayw) / 2), y); // center the day-name
}
}
// then the calendar itself
dc.SetTextForeground(*wxBLACK);
//dc.SetFont(*wxNORMAL_FONT);
y += m_heightRow;
wxDateTime date = GetStartDate();
#if DEBUG_PAINT
wxLogDebug("starting calendar from %s\n",
date.Format("%a %d-%m-%Y %H:%M:%S").c_str());
#endif
dc.SetBackgroundMode(wxSOLID);
for ( size_t nWeek = 1; nWeek <= 6; nWeek++, y += m_heightRow )
{
// if the update region doesn't intersect this row, don't paint it
if ( !IsExposed(x0, y, x0 + 7*m_widthCol, m_heightRow - 1) )
{
date += wxDateSpan::Week();
continue;
}
#if DEBUG_PAINT
wxLogDebug("painting week %d at y = %d\n", nWeek, y);
#endif
for ( int wd = 0; wd < 7; wd++ )
{
dc.SetTextBackground(*wxWHITE);
if ( IsDateShown(date) )
{
// don't use wxDate::Format() which prepends 0s
unsigned int day = date.GetDay();
wxString dayStr = wxString::Format(_T("%u"), day);
wxCoord width;
dc.GetTextExtent(dayStr, &width, (wxCoord *)NULL);
bool changedColours = false,
changedFont = false;
bool isSel = false;
wxCalendarDateAttr *attr = NULL;
if ( date.GetMonth() != m_date.GetMonth() || !IsDateInRange(date) )
{
// surrounding week or out-of-range
// draw "disabled"
dc.SetTextForeground(*wxLIGHT_GREY);
changedColours = true;
}
else
{
isSel = date.IsSameDate(m_date);
attr = m_attrs[day - 1];
if ( isSel )
{
dc.SetTextForeground(m_colHighlightFg);
dc.SetTextBackground(m_colHighlightBg);
changedColours = true;
}
else if ( attr )
{
wxColour colFg, colBg;
if ( attr->IsHoliday() )
{
colFg = m_colHolidayFg;
colBg = m_colHolidayBg;
}
else
{
colFg = attr->GetTextColour();
colBg = attr->GetBackgroundColour();
}
if ( colFg.Ok() )
{
dc.SetTextForeground(colFg);
changedColours = true;
}
if ( colBg.Ok() )
{
dc.SetTextBackground(colBg);
changedColours = true;
}
if ( attr->HasFont() )
{
dc.SetFont(attr->GetFont());
changedFont = true;
}
}
}
wxCoord x = wd*m_widthCol + (m_widthCol - width) / 2 + x0;
dc.DrawText(dayStr, x, y + 1);
if ( !isSel && attr && attr->HasBorder() )
{
wxColour colBorder;
if ( attr->HasBorderColour() )
{
colBorder = attr->GetBorderColour();
}
else
{
colBorder = GetForegroundColour();
}
wxPen pen(colBorder, 1, wxSOLID);
dc.SetPen(pen);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
switch ( attr->GetBorder() )
{
case wxCAL_BORDER_SQUARE:
dc.DrawRectangle(x - 2, y,
width + 4, m_heightRow);
break;
case wxCAL_BORDER_ROUND:
dc.DrawEllipse(x - 2, y,
width + 4, m_heightRow);
break;
default:
wxFAIL_MSG(_T("unknown border type"));
}
}
if ( changedColours )
{
dc.SetTextForeground(GetForegroundColour());
dc.SetTextBackground(GetBackgroundColour());
}
if ( changedFont )
{
dc.SetFont(GetFont());
}
}
//else: just don't draw it
date += wxDateSpan::Day();
}
}
// Greying out out-of-range background
bool showSurrounding = (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) != 0;
date = ( showSurrounding ) ? GetStartDate() : wxDateTime(1, m_date.GetMonth(), m_date.GetYear());
if ( !IsDateInRange(date) )
{
wxDateTime firstOOR = GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
wxBrush oorbrush = *wxLIGHT_GREY_BRUSH;
oorbrush.SetStyle(wxFDIAGONAL_HATCH);
HighlightRange(&dc, date, firstOOR, wxTRANSPARENT_PEN, &oorbrush);
}
date = ( showSurrounding ) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear());
if ( !IsDateInRange(date) )
{
wxDateTime firstOOR = GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
wxBrush oorbrush = *wxLIGHT_GREY_BRUSH;
oorbrush.SetStyle(wxFDIAGONAL_HATCH);
HighlightRange(&dc, firstOOR, date, wxTRANSPARENT_PEN, &oorbrush);
}
#if DEBUG_PAINT
wxLogDebug("+++ finished painting");
#endif
}
void wxCalendarCtrl::RefreshDate(const wxDateTime& date)
{
RecalcGeometry();
wxRect rect;
// always refresh the whole row at once because our OnPaint() will draw
// the whole row anyhow - and this allows the small optimisation in
// OnClick() below to work
rect.x = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 );
rect.y = (m_heightRow * GetWeek(date)) + m_rowOffset;
rect.width = 7*m_widthCol;
rect.height = m_heightRow;
#ifdef __WXMSW__
// VZ: for some reason, the selected date seems to occupy more space under
// MSW - this is probably some bug in the font size calculations, but I
// don't know where exactly. This fix is ugly and leads to more
// refreshes than really needed, but without it the selected days
// leaves even more ugly underscores on screen.
rect.Inflate(0, 1);
#endif // MSW
#if DEBUG_PAINT
wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
GetWeek(date),
rect.x, rect.y,
rect.x + rect.width, rect.y + rect.height);
#endif
Refresh(true, &rect);
}
void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, const wxDateTime& todate, wxPen* pPen, wxBrush* pBrush)
{
// Highlights the given range using pen and brush
// Does nothing if todate < fromdate
#if DEBUG_PAINT
wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate.Format("%d %m %Y"), todate.Format("%d %m %Y"));
#endif
if ( todate >= fromdate )
{
// do stuff
// date-coordinates
int fd, fw;
int td, tw;
// implicit: both dates must be currently shown - checked by GetDateCoord
if ( GetDateCoord(fromdate, &fd, &fw) && GetDateCoord(todate, &td, &tw) )
{
#if DEBUG_PAINT
wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd, fw, td, tw);
#endif
if ( ( (tw - fw) == 1 ) && ( td < fd ) )
{
// special case: interval 7 days or less not in same week
// split in two separate intervals
wxDateTime tfd = fromdate + wxDateSpan::Days(7-fd);
wxDateTime ftd = tfd + wxDateSpan::Day();
#if DEBUG_PAINT
wxLogDebug("Highlight: Separate segments");
#endif
// draw separately
HighlightRange(pDC, fromdate, tfd, pPen, pBrush);
HighlightRange(pDC, ftd, todate, pPen, pBrush);
}
else
{
int numpoints;
wxPoint corners[8]; // potentially 8 corners in polygon
wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 );
if ( fw == tw )
{
// simple case: same week
numpoints = 4;
corners[0] = wxPoint(x0 + (fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset);
corners[1] = wxPoint(x0 + (fd - 1) * m_widthCol, ((fw + 1 ) * m_heightRow) + m_rowOffset);
corners[2] = wxPoint(x0 + td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset);
corners[3] = wxPoint(x0 + td * m_widthCol, (tw * m_heightRow) + m_rowOffset);
}
else
{
int cidx = 0;
// "complex" polygon
corners[cidx] = wxPoint(x0 + (fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++;
if ( fd > 1 )
{
corners[cidx] = wxPoint(x0 + (fd - 1) * m_widthCol, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++;
corners[cidx] = wxPoint(x0, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++;
}
corners[cidx] = wxPoint(x0, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++;
corners[cidx] = wxPoint(x0 + td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++;
if ( td < 7 )
{
corners[cidx] = wxPoint(x0 + td * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++;
corners[cidx] = wxPoint(x0 + 7 * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++;
}
corners[cidx] = wxPoint(x0 + 7 * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++;
numpoints = cidx;
}
// draw the polygon
pDC->SetBrush(*pBrush);
pDC->SetPen(*pPen);
pDC->DrawPolygon(numpoints, corners);
}
}
}
// else do nothing
#if DEBUG_PAINT
wxLogDebug("--- HighlightRange ---");
#endif
}
bool wxCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *week) const
{
bool retval = true;
#if DEBUG_PAINT
wxLogDebug("+++ GetDateCoord: (%s) +++", date.Format("%d %m %Y"));
#endif
if ( IsDateShown(date) )
{
bool startOnMonday = ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) != 0;
// Find day
*day = date.GetWeekDay();
if ( *day == 0 ) // sunday
{
*day = ( startOnMonday ) ? 7 : 1;
}
else
{
*day += ( startOnMonday ) ? 0 : 1;
}
int targetmonth = date.GetMonth() + (12 * date.GetYear());
int thismonth = m_date.GetMonth() + (12 * m_date.GetYear());
// Find week
if ( targetmonth == thismonth )
{
*week = GetWeek(date);
}
else
{
if ( targetmonth < thismonth )
{
*week = 1; // trivial
}
else // targetmonth > thismonth
{
wxDateTime ldcm;
int lastweek;
int lastday;
// get the datecoord of the last day in the month currently shown
#if DEBUG_PAINT
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?