calctrl.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,791 行 · 第 1/4 页
CPP
1,791 行
bool sameMonth = m_date.GetMonth() == date.GetMonth(),
sameYear = m_date.GetYear() == date.GetYear();
if ( IsDateInRange(date) )
{
if ( sameMonth && sameYear )
{
// just change the day
ChangeDay(date);
}
else
{
if ( AllowMonthChange() && (AllowYearChange() || sameYear) )
{
// change everything
m_date = date;
if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
{
// update the controls
m_comboMonth->SetSelection(m_date.GetMonth());
if ( AllowYearChange() )
{
if ( !m_userChangedYear )
m_spinYear->SetValue(m_date.Format(_T("%Y")));
}
}
// as the month changed, holidays did too
SetHolidayAttrs();
// update the calendar
Refresh();
}
else
{
// forbidden
retval = false;
}
}
}
m_userChangedYear = false;
return retval;
}
void wxCalendarCtrl::ChangeDay(const wxDateTime& date)
{
if ( m_date != date )
{
// we need to refresh the row containing the old date and the one
// containing the new one
wxDateTime dateOld = m_date;
m_date = date;
RefreshDate(dateOld);
// if the date is in the same row, it was already drawn correctly
if ( GetWeek(m_date) != GetWeek(dateOld) )
{
RefreshDate(m_date);
}
}
}
void wxCalendarCtrl::SetDateAndNotify(const wxDateTime& date)
{
wxDateTime::Tm tm1 = m_date.GetTm(),
tm2 = date.GetTm();
wxEventType type;
if ( tm1.year != tm2.year )
type = wxEVT_CALENDAR_YEAR_CHANGED;
else if ( tm1.mon != tm2.mon )
type = wxEVT_CALENDAR_MONTH_CHANGED;
else if ( tm1.mday != tm2.mday )
type = wxEVT_CALENDAR_DAY_CHANGED;
else
return;
if ( SetDate(date) )
{
GenerateEvents(type, wxEVT_CALENDAR_SEL_CHANGED);
}
}
// ----------------------------------------------------------------------------
// date range
// ----------------------------------------------------------------------------
bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime& date /* = wxDefaultDateTime */)
{
bool retval = true;
if ( !(date.IsValid()) || ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : true ) )
{
m_lowdate = date;
}
else
{
retval = false;
}
return retval;
}
bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime& date /* = wxDefaultDateTime */)
{
bool retval = true;
if ( !(date.IsValid()) || ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : true ) )
{
m_highdate = date;
}
else
{
retval = false;
}
return retval;
}
bool wxCalendarCtrl::SetDateRange(const wxDateTime& lowerdate /* = wxDefaultDateTime */, const wxDateTime& upperdate /* = wxDefaultDateTime */)
{
bool retval = true;
if (
( !( lowerdate.IsValid() ) || ( ( upperdate.IsValid() ) ? ( lowerdate <= upperdate ) : true ) ) &&
( !( upperdate.IsValid() ) || ( ( lowerdate.IsValid() ) ? ( upperdate >= lowerdate ) : true ) ) )
{
m_lowdate = lowerdate;
m_highdate = upperdate;
}
else
{
retval = false;
}
return retval;
}
// ----------------------------------------------------------------------------
// date helpers
// ----------------------------------------------------------------------------
wxDateTime wxCalendarCtrl::GetStartDate() const
{
wxDateTime::Tm tm = m_date.GetTm();
wxDateTime date = wxDateTime(1, tm.mon, tm.year);
// rewind back
date.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
? wxDateTime::Mon : wxDateTime::Sun);
if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS )
{
// We want to offset the calendar if we start on the first..
if ( date.GetDay() == 1 )
{
date -= wxDateSpan::Week();
}
}
return date;
}
bool wxCalendarCtrl::IsDateShown(const wxDateTime& date) const
{
if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) )
{
return date.GetMonth() == m_date.GetMonth();
}
else
{
return true;
}
}
bool wxCalendarCtrl::IsDateInRange(const wxDateTime& date) const
{
// Check if the given date is in the range specified
return ( ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : true )
&& ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : true ) );
}
bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const
{
bool retval = false;
if ( !(IsDateInRange(*target)) )
{
if ( target->GetYear() < m_date.GetYear() )
{
if ( target->GetYear() >= GetLowerDateLimit().GetYear() )
{
*target = GetLowerDateLimit();
retval = true;
}
else
{
*target = m_date;
}
}
else
{
if ( target->GetYear() <= GetUpperDateLimit().GetYear() )
{
*target = GetUpperDateLimit();
retval = true;
}
else
{
*target = m_date;
}
}
}
else
{
retval = true;
}
return retval;
}
bool wxCalendarCtrl::ChangeMonth(wxDateTime* target) const
{
bool retval = true;
if ( !(IsDateInRange(*target)) )
{
retval = false;
if ( target->GetMonth() < m_date.GetMonth() )
{
*target = GetLowerDateLimit();
}
else
{
*target = GetUpperDateLimit();
}
}
return retval;
}
size_t wxCalendarCtrl::GetWeek(const wxDateTime& date) const
{
size_t retval = date.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
? wxDateTime::Monday_First
: wxDateTime::Sunday_First);
if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) )
{
// we need to offset an extra week if we "start" on the 1st of the month
wxDateTime::Tm tm = date.GetTm();
wxDateTime datetest = wxDateTime(1, tm.mon, tm.year);
// rewind back
datetest.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
? wxDateTime::Mon : wxDateTime::Sun);
if ( datetest.GetDay() == 1 )
{
retval += 1;
}
}
return retval;
}
// ----------------------------------------------------------------------------
// size management
// ----------------------------------------------------------------------------
// this is a composite control and it must arrange its parts each time its
// size or position changes: the combobox and spinctrl are along the top of
// the available area and the calendar takes up therest of the space
// the static controls are supposed to be always smaller than combo/spin so we
// always use the latter for size calculations and position the static to take
// the same space
// the constants used for the layout
#define VERT_MARGIN 5 // distance between combo and calendar
#ifdef __WXMAC__
#define HORZ_MARGIN 5 // spin
#else
#define HORZ_MARGIN 15 // spin
#endif
wxSize wxCalendarCtrl::DoGetBestSize() const
{
// calc the size of the calendar
((wxCalendarCtrl *)this)->RecalcGeometry(); // const_cast
wxCoord width = 7*m_widthCol,
height = 7*m_heightRow + m_rowOffset + VERT_MARGIN;
if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
{
// the combobox doesn't report its height correctly (it returns the
// height including the drop down list) so don't use it
height += m_spinYear->GetBestSize().y;
wxCoord w2 = m_comboMonth->GetBestSize().x + HORZ_MARGIN + GetCharWidth()*6;
if (width < w2)
width = w2;
}
if ( !HasFlag(wxBORDER_NONE) )
{
// the border would clip the last line otherwise
height += 6;
width += 4;
}
wxSize best(width, height);
CacheBestSize(best);
return best;
}
void wxCalendarCtrl::DoSetSize(int x, int y,
int width, int height,
int sizeFlags)
{
wxControl::DoSetSize(x, y, width, height, sizeFlags);
}
void wxCalendarCtrl::DoMoveWindow(int x, int y, int width, int height)
{
int yDiff;
if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
{
wxSize sizeCombo = m_comboMonth->GetSize();
wxSize sizeStatic = m_staticMonth->GetSize();
wxSize sizeSpin = m_spinYear->GetSize();
int dy = (sizeCombo.y - sizeStatic.y) / 2;
m_comboMonth->Move(x, y);
m_staticMonth->SetSize(x, y + dy, sizeCombo.x, sizeStatic.y);
int xDiff = sizeCombo.x + HORZ_MARGIN;
m_spinYear->SetSize(x + xDiff, y, width - xDiff, sizeCombo.y);
m_staticYear->SetSize(x + xDiff, y + dy, width - xDiff, sizeStatic.y);
yDiff = wxMax(sizeSpin.y, sizeCombo.y) + VERT_MARGIN;
}
else // no controls on the top
{
yDiff = 0;
}
wxControl::DoMoveWindow(x, y + yDiff, width, height - yDiff);
}
void wxCalendarCtrl::DoGetPosition(int *x, int *y) const
{
wxControl::DoGetPosition(x, y);
if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
{
// our real top corner is not in this position
if ( y )
{
*y -= GetMonthControl()->GetSize().y + VERT_MARGIN;
}
}
}
void wxCalendarCtrl::DoGetSize(int *width, int *height) const
{
wxControl::DoGetSize(width, height);
if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
{
// our real height is bigger
if ( height && GetMonthControl())
{
*height += GetMonthControl()->GetSize().y + VERT_MARGIN;
}
}
}
void wxCalendarCtrl::RecalcGeometry()
{
wxClientDC dc(this);
dc.SetFont(GetFont());
// determine the column width (weekday names are not necessarily wider
// than the numbers (in some languages), so let's not assume that they are)
m_widthCol = 0;
for ( int day = 10; day <= 31; day++)
{
wxCoord width;
dc.GetTextExtent(wxString::Format(wxT("%d"), day), &width, &m_heightRow);
if ( width > m_widthCol )
{
// 1.5 times the width gives nice margins even if the weekday
// names are short
m_widthCol = width+width/2;
}
}
wxDateTime::WeekDay wd;
for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) )
{
wxCoord width;
dc.GetTextExtent(m_weekdays[wd], &width, &m_heightRow);
if ( width > m_widthCol )
{
m_widthCol = width;
}
}
// leave some margins
m_widthCol += 2;
m_heightRow += 2;
m_rowOffset = (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ? m_heightRow : 0; // conditional in relation to style
}
// ----------------------------------------------------------------------------
// drawing
// ----------------------------------------------------------------------------
void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxPaintDC dc(this);
dc.SetFont(GetFont());
RecalcGeometry();
#if DEBUG_PAINT
wxLogDebug("--- starting to paint, selection: %s, week %u\n",
m_date.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
GetWeek(m_date));
#endif
wxCoord y = 0;
wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?