X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/51317496171b33f2abb155a1214f567b79d66e43..c02f03d563e895258dcac98a2ade423a1acbf7f9:/src/generic/calctrlg.cpp diff --git a/src/generic/calctrlg.cpp b/src/generic/calctrlg.cpp index 5725f369b5..1129f56c54 100644 --- a/src/generic/calctrlg.cpp +++ b/src/generic/calctrlg.cpp @@ -96,13 +96,14 @@ wxBEGIN_FLAGS( wxCalendarCtrlStyle ) wxFLAGS_MEMBER(wxCAL_NO_MONTH_CHANGE) wxFLAGS_MEMBER(wxCAL_SEQUENTIAL_MONTH_SELECTION) wxFLAGS_MEMBER(wxCAL_SHOW_SURROUNDING_WEEKS) + wxFLAGS_MEMBER(wxCAL_SHOW_WEEK_NUMBERS) wxEND_FLAGS( wxCalendarCtrlStyle ) IMPLEMENT_DYNAMIC_CLASS_XTI(wxGenericCalendarCtrl, wxControl,"wx/calctrl.h") wxBEGIN_PROPERTIES_TABLE(wxGenericCalendarCtrl) - wxEVENT_RANGE_PROPERTY( Updated , wxEVT_CALENDAR_SEL_CHANGED , wxEVT_CALENDAR_WEEKDAY_CLICKED , wxCalendarEvent ) + wxEVENT_RANGE_PROPERTY( Updated , wxEVT_CALENDAR_SEL_CHANGED , wxEVT_CALENDAR_WEEK_CLICKED , wxCalendarEvent ) wxHIDE_PROPERTY( Children ) wxPROPERTY( Date,wxDateTime, SetDate , GetDate, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) wxPROPERTY_FLAGS( WindowStyle , wxCalendarCtrlStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style @@ -190,7 +191,8 @@ void wxGenericCalendarCtrl::Init() m_userChangedYear = false; m_widthCol = - m_heightRow = 0; + m_heightRow = + m_calendarWeekWidth = 0; wxDateTime::WeekDay wd; for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) ) @@ -211,7 +213,7 @@ void wxGenericCalendarCtrl::InitColours() m_colHighlightFg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); m_colHighlightBg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); m_colBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - m_colSorrounding = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT); + m_colSurrounding = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT); m_colHolidayFg = *wxRED; // don't set m_colHolidayBg - by default, same as our bg colour @@ -246,12 +248,11 @@ bool wxGenericCalendarCtrl::Create(wxWindow *parent, if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { CreateYearSpinCtrl(); - m_staticYear = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(_T("%Y")), + m_staticYear = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(wxT("%Y")), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); - CreateMonthComboBox(); - m_staticMonth = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(_T("%B")), + m_staticMonth = new wxStaticText(GetParent(), wxID_ANY, m_date.Format(wxT("%B")), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE); } @@ -295,7 +296,7 @@ void wxGenericCalendarCtrl::SetWindowStyleFlag(long style) // created/shown/hidden accordingly wxASSERT_MSG( (style & wxCAL_SEQUENTIAL_MONTH_SELECTION) == (m_windowStyle & wxCAL_SEQUENTIAL_MONTH_SELECTION), - _T("wxCAL_SEQUENTIAL_MONTH_SELECTION can't be changed after creation") ); + wxT("wxCAL_SEQUENTIAL_MONTH_SELECTION can't be changed after creation") ); wxControl::SetWindowStyleFlag(style); } @@ -334,18 +335,21 @@ void wxGenericCalendarCtrl::CreateMonthComboBox() void wxGenericCalendarCtrl::CreateYearSpinCtrl() { m_spinYear = new wxSpinCtrl(GetParent(), wxID_ANY, - GetDate().Format(_T("%Y")), + GetDate().Format(wxT("%Y")), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS | wxCLIP_SIBLINGS, -4300, 10000, GetDate().GetYear()); +#ifdef __WXMAC__ + m_spinYear->SetSize( 90, -1 ); +#endif m_spinYear->Connect(m_spinYear->GetId(), wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(wxGenericCalendarCtrl::OnYearTextChange), NULL, this); m_spinYear->Connect(m_spinYear->GetId(), wxEVT_COMMAND_SPINCTRL_UPDATED, - wxCommandEventHandler(wxGenericCalendarCtrl::OnYearChange), + wxSpinEventHandler(wxGenericCalendarCtrl::OnYearChange), NULL, this); } @@ -516,7 +520,7 @@ bool wxGenericCalendarCtrl::SetDate(const wxDateTime& date) if ( AllowYearChange() ) { if ( !m_userChangedYear ) - m_spinYear->SetValue(m_date.Format(_T("%Y"))); + m_spinYear->SetValue(m_date.Format(wxT("%Y"))); } } @@ -560,27 +564,10 @@ void wxGenericCalendarCtrl::ChangeDay(const wxDateTime& date) void wxGenericCalendarCtrl::SetDateAndNotify(const wxDateTime& date) { - wxDateTime::Tm tm1 = m_date.GetTm(), - tm2 = date.GetTm(); - - const bool pageChanged = tm1.year != tm2.year || tm1.mon != tm2.mon; - - if ( !pageChanged && tm1.mday == tm2.mday ) - return; - - if ( SetDate(date) ) + const wxDateTime dateOld = GetDate(); + if ( date != dateOld && SetDate(date) ) { - GenerateEvent(wxEVT_CALENDAR_SEL_CHANGED); - if ( !pageChanged ) - GenerateEvent(wxEVT_CALENDAR_PAGE_CHANGED); - - // send also one of the deprecated events - if ( tm1.year != tm2.year ) - GenerateEvent(wxEVT_CALENDAR_YEAR_CHANGED); - else if ( tm1.mon != tm2.mon ) - GenerateEvent(wxEVT_CALENDAR_MONTH_CHANGED); - else - GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED); + GenerateAllChangeEvents(dateOld); } } @@ -787,56 +774,49 @@ size_t wxGenericCalendarCtrl::GetWeek(const wxDateTime& date) const // 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 available area and the calendar takes up the rest 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 VERT_MARGIN 5 // distance between combo and calendar #define HORZ_MARGIN 5 // spin -#else -#define HORZ_MARGIN 15 // spin -#endif + wxSize wxGenericCalendarCtrl::DoGetBestSize() const { // calc the size of the calendar - wx_const_cast(wxGenericCalendarCtrl *, this)->RecalcGeometry(); + const_cast(this)->RecalcGeometry(); - wxCoord width = 7*m_widthCol, + wxCoord width = 7*m_widthCol + m_calendarWeekWidth, 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; + const wxSize bestSizeCombo = m_comboMonth->GetBestSize(); + height += wxMax(bestSizeCombo.y, m_spinYear->GetBestSize().y) + + VERT_MARGIN; +#ifdef __WXMAC__ + // the spin control get clipped otherwise + width += 25; +#endif - wxCoord w2 = m_comboMonth->GetBestSize().x + HORZ_MARGIN + GetCharWidth()*6; - if (width < w2) + wxCoord w2 = bestSizeCombo.x + HORZ_MARGIN + GetCharWidth()*6; + if ( width < w2 ) width = w2; } + wxSize best(width, height); if ( !HasFlag(wxBORDER_NONE) ) { - // the border would clip the last line otherwise - height += 6; - width += 4; + best += GetWindowBorderSize(); } - wxSize best(width, height); CacheBestSize(best); - return best; -} -void wxGenericCalendarCtrl::DoSetSize(int x, int y, - int width, int height, - int sizeFlags) -{ - wxControl::DoSetSize(x, y, width, height, sizeFlags); + return best; } void wxGenericCalendarCtrl::DoMoveWindow(int x, int y, int width, int height) @@ -849,26 +829,21 @@ void wxGenericCalendarCtrl::DoMoveWindow(int x, int y, int width, int height) wxSize sizeStatic = m_staticMonth->GetSize(); wxSize sizeSpin = m_spinYear->GetSize(); - // wxMSW sometimes reports the wrong combo height, - // so on this platform we'll use the spin control - // height instead. -#ifdef __WXMSW__ - int maxHeight = sizeSpin.y; - int requiredSpinHeight = -1; + int maxHeight = wxMax(sizeSpin.y, sizeCombo.y); + int dy = (maxHeight - sizeStatic.y) / 2; +#ifdef __WXMAC__ + m_comboMonth->Move(x, y + (maxHeight - sizeCombo.y)/2 + 2); // FIXME, something is reporting the wrong size.. #else - int maxHeight = sizeCombo.y; - int requiredSpinHeight = sizeCombo.y; + m_comboMonth->Move(x, y + (maxHeight - sizeCombo.y)/2); #endif - int dy = (maxHeight - sizeStatic.y) / 2; - m_comboMonth->Move(x, y); m_staticMonth->SetSize(x, y + dy, sizeCombo.x, -1, sizeStatic.y); int xDiff = sizeCombo.x + HORZ_MARGIN; - m_spinYear->SetSize(x + xDiff, y, width - xDiff, requiredSpinHeight); + m_spinYear->SetSize(x + xDiff, y + (maxHeight - sizeSpin.y)/2, width - xDiff, maxHeight); m_staticYear->SetSize(x + xDiff, y + dy, width - xDiff, sizeStatic.y); - yDiff = wxMax(sizeSpin.y, maxHeight) + VERT_MARGIN; + yDiff = maxHeight + VERT_MARGIN; } else // no controls on the top { @@ -878,33 +853,21 @@ void wxGenericCalendarCtrl::DoMoveWindow(int x, int y, int width, int height) wxControl::DoMoveWindow(x, y + yDiff, width, height - yDiff); } -void wxGenericCalendarCtrl::DoGetPosition(int *x, int *y) const -{ - wxControl::DoGetPosition(x, y); -#ifndef __WXPM__ - if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) && GetMonthControl() ) - { - // our real top corner is not in this position - if ( y ) - { - *y -= GetMonthControl()->GetSize().y + VERT_MARGIN; - } - } -#endif -} - void wxGenericCalendarCtrl::DoGetSize(int *width, int *height) const { - wxControl::DoGetSize(width, height); -#ifndef __WXPM__ - if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) +#ifdef __WXMAC__ + wxControl::DoGetSize( width, height ); + + if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) && m_staticMonth && height ) { - // our real height is bigger - if ( height && GetMonthControl()) - { - *height += GetMonthControl()->GetSize().y + VERT_MARGIN; - } + wxSize sizeCombo = m_comboMonth->GetEffectiveMinSize(); + wxSize sizeSpin = m_spinYear->GetSize(); + + int maxHeight = wxMax(sizeSpin.y, sizeCombo.y); + *height += maxHeight + VERT_MARGIN; } +#else + wxControl::DoGetSize( width, height ); #endif } @@ -939,6 +902,9 @@ void wxGenericCalendarCtrl::RecalcGeometry() } } + m_calendarWeekWidth = HasFlag( wxCAL_SHOW_WEEK_NUMBERS ) + ? dc.GetTextExtent( wxString::Format( wxT( "%d" ), 42 )).GetWidth() + 4 : 0; + // leave some margins m_widthCol += 2; m_heightRow += 2; @@ -965,7 +931,7 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) #endif wxCoord y = 0; - wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 ); + wxCoord x0 = m_calendarWeekWidth; if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { @@ -1068,6 +1034,24 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) //dc.SetFont(*wxNORMAL_FONT); y += m_heightRow; + + // draw column with calendar week nr + if ( HasFlag( wxCAL_SHOW_WEEK_NUMBERS ) && IsExposed( 0, y, m_calendarWeekWidth, m_heightRow * 6 )) + { + dc.SetBackgroundMode(wxTRANSPARENT); + dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID)); + dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID)); + dc.DrawRectangle( 0, y, m_calendarWeekWidth, m_heightRow * 6 ); + wxDateTime date = GetStartDate(); + for ( size_t i = 0; i < 6; ++i ) + { + const int weekNr = date.GetWeekOfYear(); + wxString text = wxString::Format( wxT( "%d" ), weekNr ); + dc.DrawText( text, m_calendarWeekWidth - dc.GetTextExtent( text ).GetWidth() - 2, y + m_heightRow * i ); + date += wxDateSpan::Week(); + } + } + wxDateTime date = GetStartDate(); #if DEBUG_PAINT @@ -1097,9 +1081,9 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) { // don't use wxDate::Format() which prepends 0s unsigned int day = date.GetDay(); - wxString dayStr = wxString::Format(_T("%u"), day); + wxString dayStr = wxString::Format(wxT("%u"), day); wxCoord width; - dc.GetTextExtent(dayStr, &width, (wxCoord *)NULL); + dc.GetTextExtent(dayStr, &width, NULL); bool changedColours = false, changedFont = false; @@ -1109,9 +1093,8 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) if ( date.GetMonth() != m_date.GetMonth() || !IsDateInRange(date) ) { - // surrounding week or out-of-range - // draw "disabled" - dc.SetTextForeground(m_colSorrounding); + // draw the days of adjacent months in different colour + dc.SetTextForeground(m_colSurrounding); changedColours = true; } else @@ -1193,7 +1176,7 @@ void wxGenericCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) break; default: - wxFAIL_MSG(_T("unknown border type")); + wxFAIL_MSG(wxT("unknown border type")); } } @@ -1251,9 +1234,9 @@ void wxGenericCalendarCtrl::RefreshDate(const wxDateTime& date) 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 + // the whole row anyhow - and this allows the small optimization in // OnClick() below to work - rect.x = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 ); + rect.x = m_calendarWeekWidth; rect.y = (m_heightRow * GetWeek(date)) + m_rowOffset; @@ -1319,7 +1302,7 @@ void wxGenericCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fro { int numpoints; wxPoint corners[8]; // potentially 8 corners in polygon - wxCoord x0 = wxMax( (GetSize().x - m_widthCol*7) /2 , 0 ); + wxCoord x0 = m_calendarWeekWidth; if ( fw == tw ) { @@ -1486,9 +1469,20 @@ void wxGenericCalendarCtrl::OnClick(wxMouseEvent& event) ChangeDay(date); GenerateEvent(wxEVT_CALENDAR_SEL_CHANGED); + + // we know that the month/year never change when the user + // clicks on the control so there is no need to call + // GenerateAllChangeEvents() here, we know which event to send GenerateEvent(wxEVT_CALENDAR_DAY_CHANGED); } - break; + break; + + case wxCAL_HITTEST_WEEK: + { + wxCalendarEvent send( this, date, wxEVT_CALENDAR_WEEK_CLICKED ); + HandleWindowEvent( send ); + } + break; case wxCAL_HITTEST_HEADER: { @@ -1506,13 +1500,17 @@ void wxGenericCalendarCtrl::OnClick(wxMouseEvent& event) break; default: - wxFAIL_MSG(_T("unknown hittest code")); + wxFAIL_MSG(wxT("unknown hittest code")); // fall through case wxCAL_HITTEST_NOWHERE: event.Skip(); break; } + + // as we don't (always) skip the message, we're not going to receive the + // focus on click by default if we don't do it ourselves + SetFocus(); } wxCalendarHitTestResult wxGenericCalendarCtrl::HitTest(const wxPoint& pos, @@ -1522,7 +1520,7 @@ wxCalendarHitTestResult wxGenericCalendarCtrl::HitTest(const wxPoint& pos, RecalcGeometry(); // the position where the calendar really begins - wxCoord x0 = wxMax((GetSize().x - m_widthCol*7)/2, 0); + wxCoord x0 = m_calendarWeekWidth; if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) ) { @@ -1563,12 +1561,30 @@ wxCalendarHitTestResult wxGenericCalendarCtrl::HitTest(const wxPoint& pos, return wxCAL_HITTEST_INCMONTH; } + } + if ( pos.x - x0 < 0 ) + { + if ( pos.x >= 0 && pos.y > m_rowOffset + m_heightRow && pos.y <= m_rowOffset + m_heightRow * 7 ) + { + if ( date ) + { + *date = GetStartDate(); + *date += wxDateSpan::Week() * (( pos.y - m_rowOffset ) / m_heightRow - 1 ); + } + if ( wd ) + *wd = ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) ? wxDateTime::Mon : wxDateTime::Sun; + return wxCAL_HITTEST_WEEK; + } + else // early exit -> the rest of the function checks for clicks on days + return wxCAL_HITTEST_NOWHERE; } // header: week days int wday = (pos.x - x0) / m_widthCol; - if ( pos.y < (m_heightRow + m_rowOffset) ) + if ( wday > 6 ) + return wxCAL_HITTEST_NOWHERE; + if ( pos.y < (m_heightRow + m_rowOffset)) { if ( pos.y > m_rowOffset ) { @@ -1639,7 +1655,7 @@ void wxGenericCalendarCtrl::OnMonthChange(wxCommandEvent& event) SetDateAndNotify(target); } -void wxGenericCalendarCtrl::OnYearChange(wxCommandEvent& event) +void wxGenericCalendarCtrl::HandleYearChange(wxCommandEvent& event) { int year = (int)event.GetInt(); if ( year == INT_MIN ) @@ -1669,10 +1685,15 @@ void wxGenericCalendarCtrl::OnYearChange(wxCommandEvent& event) } } +void wxGenericCalendarCtrl::OnYearChange(wxSpinEvent& event) +{ + HandleYearChange( event ); +} + void wxGenericCalendarCtrl::OnYearTextChange(wxCommandEvent& event) { SetUserChangedYear(); - OnYearChange(event); + HandleYearChange(event); } // Responds to colour changes, and passes event on to children. @@ -1698,7 +1719,7 @@ void wxGenericCalendarCtrl::OnChar(wxKeyEvent& event) wxDateTime target; switch ( event.GetKeyCode() ) { - case _T('+'): + case wxT('+'): case WXK_ADD: target = m_date + wxDateSpan::Year(); if ( ChangeYear(&target) ) @@ -1707,7 +1728,7 @@ void wxGenericCalendarCtrl::OnChar(wxKeyEvent& event) } break; - case _T('-'): + case wxT('-'): case WXK_SUBTRACT: target = m_date - wxDateSpan::Year(); if ( ChangeYear(&target) ) @@ -1792,48 +1813,9 @@ void wxGenericCalendarCtrl::OnChar(wxKeyEvent& event) // holidays handling // ---------------------------------------------------------------------------- -void wxGenericCalendarCtrl::EnableHolidayDisplay(bool display) -{ - long style = GetWindowStyle(); - if ( display ) - style |= wxCAL_SHOW_HOLIDAYS; - else - style &= ~wxCAL_SHOW_HOLIDAYS; - - SetWindowStyle(style); - - if ( display ) - SetHolidayAttrs(); - else - ResetHolidayAttrs(); - - Refresh(); -} - -void wxGenericCalendarCtrl::SetHolidayAttrs() -{ - if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS ) - { - ResetHolidayAttrs(); - - wxDateTime::Tm tm = m_date.GetTm(); - wxDateTime dtStart(1, tm.mon, tm.year), - dtEnd = dtStart.GetLastMonthDay(); - - wxDateTimeArray hol; - wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart, dtEnd, hol); - - size_t count = hol.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - SetHoliday(hol[n].GetDay()); - } - } -} - void wxGenericCalendarCtrl::SetHoliday(size_t day) { - wxCHECK_RET( day > 0 && day < 32, _T("invalid day in SetHoliday") ); + wxCHECK_RET( day > 0 && day < 32, wxT("invalid day in SetHoliday") ); wxCalendarDateAttr *attr = GetAttr(day); if ( !attr ) @@ -1860,7 +1842,7 @@ void wxGenericCalendarCtrl::ResetHolidayAttrs() void wxGenericCalendarCtrl::Mark(size_t day, bool mark) { - wxCHECK_RET( day > 0 && day < 32, _T("invalid day in Mark") ); + wxCHECK_RET( day > 0 && day < 32, wxT("invalid day in Mark") ); const wxCalendarDateAttr& m = wxCalendarDateAttr::GetMark(); if (mark) {