1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: generic/calctrl.cpp
3 // Purpose: implementation fo the generic wxCalendarCtrl
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "calctrl.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
32 #include "wx/dcclient.h"
33 #include "wx/settings.h"
35 #include "wx/combobox.h"
36 #include "wx/listbox.h"
37 #include "wx/stattext.h"
38 #include "wx/textctrl.h"
41 #if wxUSE_CALENDARCTRL
43 #include "wx/spinctrl.h"
45 #include "wx/calctrl.h"
49 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 class wxMonthComboBox
: public wxComboBox
56 wxMonthComboBox(wxCalendarCtrl
*cal
);
58 void OnMonthChange(wxCommandEvent
& event
) { m_cal
->OnMonthChange(event
); }
61 wxCalendarCtrl
*m_cal
;
64 DECLARE_NO_COPY_CLASS(wxMonthComboBox
)
67 class wxYearSpinCtrl
: public wxSpinCtrl
70 wxYearSpinCtrl(wxCalendarCtrl
*cal
);
72 void OnYearTextChange(wxCommandEvent
& event
)
74 m_cal
->SetUserChangedYear();
75 m_cal
->OnYearChange(event
);
77 void OnYearChange(wxSpinEvent
& event
) { m_cal
->OnYearChange(event
); }
80 wxCalendarCtrl
*m_cal
;
83 DECLARE_NO_COPY_CLASS(wxYearSpinCtrl
)
86 // ----------------------------------------------------------------------------
88 // ----------------------------------------------------------------------------
90 BEGIN_EVENT_TABLE(wxCalendarCtrl
, wxControl
)
91 EVT_PAINT(wxCalendarCtrl::OnPaint
)
93 EVT_CHAR(wxCalendarCtrl::OnChar
)
95 EVT_LEFT_DOWN(wxCalendarCtrl::OnClick
)
96 EVT_LEFT_DCLICK(wxCalendarCtrl::OnDClick
)
99 BEGIN_EVENT_TABLE(wxMonthComboBox
, wxComboBox
)
100 EVT_COMBOBOX(wxID_ANY
, wxMonthComboBox::OnMonthChange
)
103 BEGIN_EVENT_TABLE(wxYearSpinCtrl
, wxSpinCtrl
)
104 EVT_TEXT(wxID_ANY
, wxYearSpinCtrl::OnYearTextChange
)
105 EVT_SPINCTRL(wxID_ANY
, wxYearSpinCtrl::OnYearChange
)
108 #if wxUSE_EXTENDED_RTTI
109 WX_DEFINE_FLAGS( wxCalendarCtrlStyle
)
111 wxBEGIN_FLAGS( wxCalendarCtrlStyle
)
112 // new style border flags, we put them first to
113 // use them for streaming out
114 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
115 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
116 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
117 wxFLAGS_MEMBER(wxBORDER_RAISED
)
118 wxFLAGS_MEMBER(wxBORDER_STATIC
)
119 wxFLAGS_MEMBER(wxBORDER_NONE
)
121 // old style border flags
122 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
123 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
124 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
125 wxFLAGS_MEMBER(wxRAISED_BORDER
)
126 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
127 wxFLAGS_MEMBER(wxBORDER
)
129 // standard window styles
130 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
131 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
132 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
133 wxFLAGS_MEMBER(wxWANTS_CHARS
)
134 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
135 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
136 wxFLAGS_MEMBER(wxVSCROLL
)
137 wxFLAGS_MEMBER(wxHSCROLL
)
139 wxFLAGS_MEMBER(wxCAL_SUNDAY_FIRST
)
140 wxFLAGS_MEMBER(wxCAL_MONDAY_FIRST
)
141 wxFLAGS_MEMBER(wxCAL_SHOW_HOLIDAYS
)
142 wxFLAGS_MEMBER(wxCAL_NO_YEAR_CHANGE
)
143 wxFLAGS_MEMBER(wxCAL_NO_MONTH_CHANGE
)
144 wxFLAGS_MEMBER(wxCAL_SEQUENTIAL_MONTH_SELECTION
)
145 wxFLAGS_MEMBER(wxCAL_SHOW_SURROUNDING_WEEKS
)
147 wxEND_FLAGS( wxCalendarCtrlStyle
)
149 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCalendarCtrl
, wxControl
,"wx/calctrl.h")
151 wxBEGIN_PROPERTIES_TABLE(wxCalendarCtrl
)
152 wxEVENT_RANGE_PROPERTY( Updated
, wxEVT_CALENDAR_SEL_CHANGED
, wxEVT_CALENDAR_WEEKDAY_CLICKED
, wxCalendarEvent
)
153 wxHIDE_PROPERTY( Children
)
154 wxPROPERTY( Date
,wxDateTime
, SetDate
, GetDate
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
155 wxPROPERTY_FLAGS( WindowStyle
, wxCalendarCtrlStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
156 wxEND_PROPERTIES_TABLE()
158 wxBEGIN_HANDLERS_TABLE(wxCalendarCtrl
)
159 wxEND_HANDLERS_TABLE()
161 wxCONSTRUCTOR_6( wxCalendarCtrl
, wxWindow
* , Parent
, wxWindowID
, Id
, wxDateTime
, Date
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
163 IMPLEMENT_DYNAMIC_CLASS(wxCalendarCtrl
, wxControl
)
165 IMPLEMENT_DYNAMIC_CLASS(wxCalendarEvent
, wxCommandEvent
)
167 // ----------------------------------------------------------------------------
169 // ----------------------------------------------------------------------------
171 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_SEL_CHANGED
)
172 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DAY_CHANGED
)
173 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_MONTH_CHANGED
)
174 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_YEAR_CHANGED
)
175 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DOUBLECLICKED
)
176 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_WEEKDAY_CLICKED
)
178 // ============================================================================
180 // ============================================================================
182 // ----------------------------------------------------------------------------
183 // wxMonthComboBox and wxYearSpinCtrl
184 // ----------------------------------------------------------------------------
186 wxMonthComboBox::wxMonthComboBox(wxCalendarCtrl
*cal
)
187 : wxComboBox(cal
->GetParent(), wxID_ANY
,
192 wxCB_READONLY
| wxCLIP_SIBLINGS
)
197 for ( m
= wxDateTime::Jan
; m
< wxDateTime::Inv_Month
; wxNextMonth(m
) )
199 Append(wxDateTime::GetMonthName(m
));
202 SetSelection(m_cal
->GetDate().GetMonth());
203 SetSize(wxDefaultCoord
,
207 wxSIZE_AUTO_WIDTH
|wxSIZE_AUTO_HEIGHT
);
210 wxYearSpinCtrl::wxYearSpinCtrl(wxCalendarCtrl
*cal
)
211 : wxSpinCtrl(cal
->GetParent(), wxID_ANY
,
212 cal
->GetDate().Format(_T("%Y")),
215 wxSP_ARROW_KEYS
| wxCLIP_SIBLINGS
,
216 -4300, 10000, cal
->GetDate().GetYear())
222 // ----------------------------------------------------------------------------
224 // ----------------------------------------------------------------------------
226 wxCalendarCtrl::wxCalendarCtrl(wxWindow
*parent
,
228 const wxDateTime
& date
,
232 const wxString
& name
)
236 (void)Create(parent
, id
, date
, pos
, size
, style
, name
);
239 void wxCalendarCtrl::Init()
244 m_staticMonth
= NULL
;
246 m_userChangedYear
= false;
251 wxDateTime::WeekDay wd
;
252 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
254 m_weekdays
[wd
] = wxDateTime::GetWeekDayName(wd
, wxDateTime::Name_Abbr
);
257 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
262 m_colHighlightFg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
263 m_colHighlightBg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
);
265 m_colHolidayFg
= *wxRED
;
266 // don't set m_colHolidayBg - by default, same as our bg colour
268 m_colHeaderFg
= *wxBLUE
;
269 m_colHeaderBg
= *wxLIGHT_GREY
;
272 bool wxCalendarCtrl::Create(wxWindow
*parent
,
274 const wxDateTime
& date
,
278 const wxString
& name
)
280 if ( !wxControl::Create(parent
, id
, pos
, size
,
281 style
| wxCLIP_CHILDREN
| wxWANTS_CHARS
,
282 wxDefaultValidator
, name
) )
287 // needed to get the arrow keys normally used for the dialog navigation
288 SetWindowStyle(style
| wxWANTS_CHARS
);
290 m_date
= date
.IsValid() ? date
: wxDateTime::Today();
292 m_lowdate
= wxDefaultDateTime
;
293 m_highdate
= wxDefaultDateTime
;
295 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
297 m_spinYear
= new wxYearSpinCtrl(this);
298 m_staticYear
= new wxStaticText(GetParent(), wxID_ANY
, m_date
.Format(_T("%Y")),
299 wxDefaultPosition
, wxDefaultSize
,
302 m_comboMonth
= new wxMonthComboBox(this);
303 m_staticMonth
= new wxStaticText(GetParent(), wxID_ANY
, m_date
.Format(_T("%B")),
304 wxDefaultPosition
, wxDefaultSize
,
308 ShowCurrentControls();
310 // we need to set the position as well because the main control position
311 // is not the same as the one specified in pos if we have the controls
316 // Since we don't paint the whole background make sure that the platform
317 // will use the right one.
318 SetBackgroundColour(GetBackgroundColour());
325 wxCalendarCtrl::~wxCalendarCtrl()
327 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
333 // ----------------------------------------------------------------------------
334 // forward wxWin functions to subcontrols
335 // ----------------------------------------------------------------------------
337 bool wxCalendarCtrl::Destroy()
340 m_staticYear
->Destroy();
342 m_spinYear
->Destroy();
344 m_comboMonth
->Destroy();
346 m_staticMonth
->Destroy();
351 m_staticMonth
= NULL
;
353 return wxControl::Destroy();
356 bool wxCalendarCtrl::Show(bool show
)
358 if ( !wxControl::Show(show
) )
363 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
365 if ( GetMonthControl() )
367 GetMonthControl()->Show(show
);
368 GetYearControl()->Show(show
);
375 bool wxCalendarCtrl::Enable(bool enable
)
377 if ( !wxControl::Enable(enable
) )
382 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
384 GetMonthControl()->Enable(enable
);
385 GetYearControl()->Enable(enable
);
391 // ----------------------------------------------------------------------------
392 // enable/disable month/year controls
393 // ----------------------------------------------------------------------------
395 void wxCalendarCtrl::ShowCurrentControls()
397 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
399 if ( AllowMonthChange() )
401 m_comboMonth
->Show();
402 m_staticMonth
->Hide();
404 if ( AllowYearChange() )
407 m_staticYear
->Hide();
415 m_comboMonth
->Hide();
416 m_staticMonth
->Show();
419 // year change not allowed here
421 m_staticYear
->Show();
425 wxControl
*wxCalendarCtrl::GetMonthControl() const
427 return AllowMonthChange() ? (wxControl
*)m_comboMonth
: (wxControl
*)m_staticMonth
;
430 wxControl
*wxCalendarCtrl::GetYearControl() const
432 return AllowYearChange() ? (wxControl
*)m_spinYear
: (wxControl
*)m_staticYear
;
435 void wxCalendarCtrl::EnableYearChange(bool enable
)
437 if ( enable
!= AllowYearChange() )
439 long style
= GetWindowStyle();
441 style
&= ~wxCAL_NO_YEAR_CHANGE
;
443 style
|= wxCAL_NO_YEAR_CHANGE
;
444 SetWindowStyle(style
);
446 ShowCurrentControls();
447 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
454 void wxCalendarCtrl::EnableMonthChange(bool enable
)
456 if ( enable
!= AllowMonthChange() )
458 long style
= GetWindowStyle();
460 style
&= ~wxCAL_NO_MONTH_CHANGE
;
462 style
|= wxCAL_NO_MONTH_CHANGE
;
463 SetWindowStyle(style
);
465 ShowCurrentControls();
466 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
473 // ----------------------------------------------------------------------------
475 // ----------------------------------------------------------------------------
477 bool wxCalendarCtrl::SetDate(const wxDateTime
& date
)
481 bool sameMonth
= m_date
.GetMonth() == date
.GetMonth(),
482 sameYear
= m_date
.GetYear() == date
.GetYear();
484 if ( IsDateInRange(date
) )
486 if ( sameMonth
&& sameYear
)
488 // just change the day
493 if ( AllowMonthChange() && (AllowYearChange() || sameYear
) )
498 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
500 // update the controls
501 m_comboMonth
->SetSelection(m_date
.GetMonth());
503 if ( AllowYearChange() )
505 if ( !m_userChangedYear
)
506 m_spinYear
->SetValue(m_date
.Format(_T("%Y")));
510 // as the month changed, holidays did too
513 // update the calendar
524 m_userChangedYear
= false;
529 void wxCalendarCtrl::ChangeDay(const wxDateTime
& date
)
531 if ( m_date
!= date
)
533 // we need to refresh the row containing the old date and the one
534 // containing the new one
535 wxDateTime dateOld
= m_date
;
538 RefreshDate(dateOld
);
540 // if the date is in the same row, it was already drawn correctly
541 if ( GetWeek(m_date
) != GetWeek(dateOld
) )
548 void wxCalendarCtrl::SetDateAndNotify(const wxDateTime
& date
)
550 wxDateTime::Tm tm1
= m_date
.GetTm(),
554 if ( tm1
.year
!= tm2
.year
)
555 type
= wxEVT_CALENDAR_YEAR_CHANGED
;
556 else if ( tm1
.mon
!= tm2
.mon
)
557 type
= wxEVT_CALENDAR_MONTH_CHANGED
;
558 else if ( tm1
.mday
!= tm2
.mday
)
559 type
= wxEVT_CALENDAR_DAY_CHANGED
;
565 GenerateEvents(type
, wxEVT_CALENDAR_SEL_CHANGED
);
569 // ----------------------------------------------------------------------------
571 // ----------------------------------------------------------------------------
573 bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
577 if ( !(date
.IsValid()) || ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) )
589 bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
593 if ( !(date
.IsValid()) || ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true ) )
605 bool wxCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
/* = wxDefaultDateTime */, const wxDateTime
& upperdate
/* = wxDefaultDateTime */)
610 ( !( lowerdate
.IsValid() ) || ( ( upperdate
.IsValid() ) ? ( lowerdate
<= upperdate
) : true ) ) &&
611 ( !( upperdate
.IsValid() ) || ( ( lowerdate
.IsValid() ) ? ( upperdate
>= lowerdate
) : true ) ) )
613 m_lowdate
= lowerdate
;
614 m_highdate
= upperdate
;
624 // ----------------------------------------------------------------------------
626 // ----------------------------------------------------------------------------
628 wxDateTime
wxCalendarCtrl::GetStartDate() const
630 wxDateTime::Tm tm
= m_date
.GetTm();
632 wxDateTime date
= wxDateTime(1, tm
.mon
, tm
.year
);
635 date
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
636 ? wxDateTime::Mon
: wxDateTime::Sun
);
638 if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
)
640 // We want to offset the calendar if we start on the first..
641 if ( date
.GetDay() == 1 )
643 date
-= wxDateSpan::Week();
650 bool wxCalendarCtrl::IsDateShown(const wxDateTime
& date
) const
652 if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
654 return date
.GetMonth() == m_date
.GetMonth();
662 bool wxCalendarCtrl::IsDateInRange(const wxDateTime
& date
) const
664 // Check if the given date is in the range specified
665 return ( ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true )
666 && ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) );
669 bool wxCalendarCtrl::ChangeYear(wxDateTime
* target
) const
673 if ( !(IsDateInRange(*target
)) )
675 if ( target
->GetYear() < m_date
.GetYear() )
677 if ( target
->GetYear() >= GetLowerDateLimit().GetYear() )
679 *target
= GetLowerDateLimit();
689 if ( target
->GetYear() <= GetUpperDateLimit().GetYear() )
691 *target
= GetUpperDateLimit();
708 bool wxCalendarCtrl::ChangeMonth(wxDateTime
* target
) const
712 if ( !(IsDateInRange(*target
)) )
716 if ( target
->GetMonth() < m_date
.GetMonth() )
718 *target
= GetLowerDateLimit();
722 *target
= GetUpperDateLimit();
729 size_t wxCalendarCtrl::GetWeek(const wxDateTime
& date
) const
731 size_t retval
= date
.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
732 ? wxDateTime::Monday_First
733 : wxDateTime::Sunday_First
);
735 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
737 // we need to offset an extra week if we "start" on the 1st of the month
738 wxDateTime::Tm tm
= date
.GetTm();
740 wxDateTime datetest
= wxDateTime(1, tm
.mon
, tm
.year
);
743 datetest
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
744 ? wxDateTime::Mon
: wxDateTime::Sun
);
746 if ( datetest
.GetDay() == 1 )
755 // ----------------------------------------------------------------------------
757 // ----------------------------------------------------------------------------
759 // this is a composite control and it must arrange its parts each time its
760 // size or position changes: the combobox and spinctrl are along the top of
761 // the available area and the calendar takes up therest of the space
763 // the static controls are supposed to be always smaller than combo/spin so we
764 // always use the latter for size calculations and position the static to take
767 // the constants used for the layout
768 #define VERT_MARGIN 5 // distance between combo and calendar
770 #define HORZ_MARGIN 5 // spin
772 #define HORZ_MARGIN 15 // spin
774 wxSize
wxCalendarCtrl::DoGetBestSize() const
776 // calc the size of the calendar
777 ((wxCalendarCtrl
*)this)->RecalcGeometry(); // const_cast
779 wxCoord width
= 7*m_widthCol
,
780 height
= 7*m_heightRow
+ m_rowOffset
+ VERT_MARGIN
;
782 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
784 // the combobox doesn't report its height correctly (it returns the
785 // height including the drop down list) so don't use it
786 height
+= m_spinYear
->GetBestSize().y
;
789 if ( !HasFlag(wxBORDER_NONE
) )
791 // the border would clip the last line otherwise
796 wxSize
best(width
, height
);
801 void wxCalendarCtrl::DoSetSize(int x
, int y
,
802 int width
, int height
,
805 wxControl::DoSetSize(x
, y
, width
, height
, sizeFlags
);
808 void wxCalendarCtrl::DoMoveWindow(int x
, int y
, int width
, int height
)
812 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
814 wxSize sizeCombo
= m_comboMonth
->GetSize();
815 wxSize sizeStatic
= m_staticMonth
->GetSize();
816 wxSize sizeSpin
= m_spinYear
->GetSize();
817 int dy
= (sizeCombo
.y
- sizeStatic
.y
) / 2;
819 In the calender the size of the combobox for the year
820 is just defined by a margin from the month combobox to
821 the left border. While in wxUniv the year control can't
822 show all 4 digits, in wxMsw it show almost twice as
823 much. Instead the year should use it's best size and be
824 left aligned to the calendar. Just in case the month in
825 any language is longer than it has space in the
826 calendar it is shortend.This way the year always can
829 This patch relies on the fact that a combobox has a
830 good best size implementation. This is not the case
831 with wxMSW but I don't know why.
836 #ifdef __WXUNIVERSAL__
837 if (sizeCombo
.x
+ HORZ_MARGIN
- sizeSpin
.x
> width
)
839 m_comboMonth
->SetSize(x
, y
, width
- HORZ_MARGIN
- sizeSpin
.x
, sizeCombo
.y
);
843 m_comboMonth
->Move(x
, y
);
845 m_staticMonth
->Move(x
, y
+ dy
);
846 m_spinYear
->Move(x
+ width
- sizeSpin
.x
, y
);
847 m_staticYear
->Move(x
+ width
- sizeSpin
.x
, y
+ dy
);
849 m_comboMonth
->Move(x
, y
);
850 m_staticMonth
->SetSize(x
, y
+ dy
, sizeCombo
.x
, sizeStatic
.y
);
852 int xDiff
= sizeCombo
.x
+ HORZ_MARGIN
;
854 m_spinYear
->SetSize(x
+ xDiff
, y
, width
- xDiff
, sizeCombo
.y
);
855 m_staticYear
->SetSize(x
+ xDiff
, y
+ dy
, width
- xDiff
, sizeStatic
.y
);
857 yDiff
= wxMax(sizeSpin
.y
, sizeCombo
.y
) + VERT_MARGIN
;
859 else // no controls on the top
864 wxControl::DoMoveWindow(x
, y
+ yDiff
, width
, height
- yDiff
);
867 void wxCalendarCtrl::DoGetPosition(int *x
, int *y
) const
869 wxControl::DoGetPosition(x
, y
);
871 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
873 // our real top corner is not in this position
876 *y
-= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
881 void wxCalendarCtrl::DoGetSize(int *width
, int *height
) const
883 wxControl::DoGetSize(width
, height
);
885 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
887 // our real height is bigger
888 if ( height
&& GetMonthControl())
890 *height
+= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
895 void wxCalendarCtrl::RecalcGeometry()
899 dc
.SetFont(GetFont());
901 // determine the column width (we assume that the weekday names are always
902 // wider (in any language) than the numbers)
904 wxDateTime::WeekDay wd
;
905 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
908 dc
.GetTextExtent(m_weekdays
[wd
], &width
, &m_heightRow
);
909 if ( width
> m_widthCol
)
915 // leave some margins
919 m_rowOffset
= (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) ? m_heightRow
: 0; // conditional in relation to style
922 // ----------------------------------------------------------------------------
924 // ----------------------------------------------------------------------------
926 void wxCalendarCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
))
930 dc
.SetFont(GetFont());
935 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
936 m_date
.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
942 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
944 // draw the sequential month-selector
946 dc
.SetBackgroundMode(wxTRANSPARENT
);
947 dc
.SetTextForeground(*wxBLACK
);
948 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
949 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
950 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
952 // Get extent of month-name + year
953 wxCoord monthw
, monthh
;
954 wxString headertext
= m_date
.Format(wxT("%B %Y"));
955 dc
.GetTextExtent(headertext
, &monthw
, &monthh
);
957 // draw month-name centered above weekdays
958 wxCoord monthx
= ((m_widthCol
* 7) - monthw
) / 2;
959 wxCoord monthy
= ((m_heightRow
- monthh
) / 2) + y
;
960 dc
.DrawText(headertext
, monthx
, monthy
);
962 // calculate the "month-arrows"
963 wxPoint leftarrow
[3];
964 wxPoint rightarrow
[3];
966 int arrowheight
= monthh
/ 2;
968 leftarrow
[0] = wxPoint(0, arrowheight
/ 2);
969 leftarrow
[1] = wxPoint(arrowheight
/ 2, 0);
970 leftarrow
[2] = wxPoint(arrowheight
/ 2, arrowheight
- 1);
972 rightarrow
[0] = wxPoint(0, 0);
973 rightarrow
[1] = wxPoint(arrowheight
/ 2, arrowheight
/ 2);
974 rightarrow
[2] = wxPoint(0, arrowheight
- 1);
976 // draw the "month-arrows"
978 wxCoord arrowy
= (m_heightRow
- arrowheight
) / 2;
979 wxCoord larrowx
= (m_widthCol
- (arrowheight
/ 2)) / 2;
980 wxCoord rarrowx
= ((m_widthCol
- (arrowheight
/ 2)) / 2) + m_widthCol
*6;
981 m_leftArrowRect
= wxRect(0, 0, 0, 0);
982 m_rightArrowRect
= wxRect(0, 0, 0, 0);
984 if ( AllowMonthChange() )
986 wxDateTime ldpm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) - wxDateSpan::Day(); // last day prev month
987 // Check if range permits change
988 if ( IsDateInRange(ldpm
) && ( ( ldpm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
990 m_leftArrowRect
= wxRect(larrowx
- 3, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
991 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
992 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
993 dc
.DrawPolygon(3, leftarrow
, larrowx
, arrowy
, wxWINDING_RULE
);
994 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
995 dc
.DrawRectangle(m_leftArrowRect
);
997 wxDateTime fdnm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) + wxDateSpan::Month(); // first day next month
998 if ( IsDateInRange(fdnm
) && ( ( fdnm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
1000 m_rightArrowRect
= wxRect(rarrowx
- 4, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1001 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1002 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1003 dc
.DrawPolygon(3, rightarrow
, rarrowx
, arrowy
, wxWINDING_RULE
);
1004 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1005 dc
.DrawRectangle(m_rightArrowRect
);
1012 // first draw the week days
1013 if ( IsExposed(0, y
, 7*m_widthCol
, m_heightRow
) )
1016 wxLogDebug("painting the header");
1019 dc
.SetBackgroundMode(wxTRANSPARENT
);
1020 dc
.SetTextForeground(m_colHeaderFg
);
1021 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
1022 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
1023 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
1025 bool startOnMonday
= (GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1026 for ( size_t wd
= 0; wd
< 7; wd
++ )
1029 if ( startOnMonday
)
1030 n
= wd
== 6 ? 0 : wd
+ 1;
1034 dc
.GetTextExtent(m_weekdays
[n
], &dayw
, &dayh
);
1035 dc
.DrawText(m_weekdays
[n
], (wd
*m_widthCol
) + ((m_widthCol
- dayw
) / 2), y
); // center the day-name
1039 // then the calendar itself
1040 dc
.SetTextForeground(*wxBLACK
);
1041 //dc.SetFont(*wxNORMAL_FONT);
1044 wxDateTime date
= GetStartDate();
1047 wxLogDebug("starting calendar from %s\n",
1048 date
.Format("%a %d-%m-%Y %H:%M:%S").c_str());
1051 dc
.SetBackgroundMode(wxSOLID
);
1052 for ( size_t nWeek
= 1; nWeek
<= 6; nWeek
++, y
+= m_heightRow
)
1054 // if the update region doesn't intersect this row, don't paint it
1055 if ( !IsExposed(0, y
, 7*m_widthCol
, m_heightRow
- 1) )
1057 date
+= wxDateSpan::Week();
1063 wxLogDebug("painting week %d at y = %d\n", nWeek
, y
);
1066 for ( size_t wd
= 0; wd
< 7; wd
++ )
1068 if ( IsDateShown(date
) )
1070 // don't use wxDate::Format() which prepends 0s
1071 unsigned int day
= date
.GetDay();
1072 wxString dayStr
= wxString::Format(_T("%u"), day
);
1074 dc
.GetTextExtent(dayStr
, &width
, (wxCoord
*)NULL
);
1076 bool changedColours
= false,
1077 changedFont
= false;
1080 wxCalendarDateAttr
*attr
= NULL
;
1082 if ( date
.GetMonth() != m_date
.GetMonth() || !IsDateInRange(date
) )
1084 // surrounding week or out-of-range
1086 dc
.SetTextForeground(*wxLIGHT_GREY
);
1087 changedColours
= true;
1091 isSel
= date
.IsSameDate(m_date
);
1092 attr
= m_attrs
[day
- 1];
1096 dc
.SetTextForeground(m_colHighlightFg
);
1097 dc
.SetTextBackground(m_colHighlightBg
);
1099 changedColours
= true;
1103 wxColour colFg
, colBg
;
1105 if ( attr
->IsHoliday() )
1107 colFg
= m_colHolidayFg
;
1108 colBg
= m_colHolidayBg
;
1112 colFg
= attr
->GetTextColour();
1113 colBg
= attr
->GetBackgroundColour();
1118 dc
.SetTextForeground(colFg
);
1119 changedColours
= true;
1124 dc
.SetTextBackground(colBg
);
1125 changedColours
= true;
1128 if ( attr
->HasFont() )
1130 dc
.SetFont(attr
->GetFont());
1136 wxCoord x
= wd
*m_widthCol
+ (m_widthCol
- width
) / 2;
1137 dc
.DrawText(dayStr
, x
, y
+ 1);
1139 if ( !isSel
&& attr
&& attr
->HasBorder() )
1142 if ( attr
->HasBorderColour() )
1144 colBorder
= attr
->GetBorderColour();
1148 colBorder
= GetForegroundColour();
1151 wxPen
pen(colBorder
, 1, wxSOLID
);
1153 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1155 switch ( attr
->GetBorder() )
1157 case wxCAL_BORDER_SQUARE
:
1158 dc
.DrawRectangle(x
- 2, y
,
1159 width
+ 4, m_heightRow
);
1162 case wxCAL_BORDER_ROUND
:
1163 dc
.DrawEllipse(x
- 2, y
,
1164 width
+ 4, m_heightRow
);
1168 wxFAIL_MSG(_T("unknown border type"));
1172 if ( changedColours
)
1174 dc
.SetTextForeground(GetForegroundColour());
1175 dc
.SetTextBackground(GetBackgroundColour());
1180 dc
.SetFont(GetFont());
1183 //else: just don't draw it
1185 date
+= wxDateSpan::Day();
1189 // Greying out out-of-range background
1190 bool showSurrounding
= (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) != 0;
1192 date
= ( showSurrounding
) ? GetStartDate() : wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear());
1193 if ( !IsDateInRange(date
) )
1195 wxDateTime firstOOR
= GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1197 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1198 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1200 HighlightRange(&dc
, date
, firstOOR
, wxTRANSPARENT_PEN
, &oorbrush
);
1203 date
= ( showSurrounding
) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear());
1204 if ( !IsDateInRange(date
) )
1206 wxDateTime firstOOR
= GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1208 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1209 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1211 HighlightRange(&dc
, firstOOR
, date
, wxTRANSPARENT_PEN
, &oorbrush
);
1215 wxLogDebug("+++ finished painting");
1219 void wxCalendarCtrl::RefreshDate(const wxDateTime
& date
)
1225 // always refresh the whole row at once because our OnPaint() will draw
1226 // the whole row anyhow - and this allows the small optimisation in
1227 // OnClick() below to work
1230 rect
.y
= (m_heightRow
* GetWeek(date
)) + m_rowOffset
;
1232 rect
.width
= 7*m_widthCol
;
1233 rect
.height
= m_heightRow
;
1236 // VZ: for some reason, the selected date seems to occupy more space under
1237 // MSW - this is probably some bug in the font size calculations, but I
1238 // don't know where exactly. This fix is ugly and leads to more
1239 // refreshes than really needed, but without it the selected days
1240 // leaves even more ugly underscores on screen.
1245 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
1248 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
1251 Refresh(true, &rect
);
1254 void wxCalendarCtrl::HighlightRange(wxPaintDC
* pDC
, const wxDateTime
& fromdate
, const wxDateTime
& todate
, wxPen
* pPen
, wxBrush
* pBrush
)
1256 // Highlights the given range using pen and brush
1257 // Does nothing if todate < fromdate
1261 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate
.Format("%d %m %Y"), todate
.Format("%d %m %Y"));
1264 if ( todate
>= fromdate
)
1271 // implicit: both dates must be currently shown - checked by GetDateCoord
1272 if ( GetDateCoord(fromdate
, &fd
, &fw
) && GetDateCoord(todate
, &td
, &tw
) )
1275 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd
, fw
, td
, tw
);
1277 if ( ( (tw
- fw
) == 1 ) && ( td
< fd
) )
1279 // special case: interval 7 days or less not in same week
1280 // split in two seperate intervals
1281 wxDateTime tfd
= fromdate
+ wxDateSpan::Days(7-fd
);
1282 wxDateTime ftd
= tfd
+ wxDateSpan::Day();
1284 wxLogDebug("Highlight: Seperate segments");
1287 HighlightRange(pDC
, fromdate
, tfd
, pPen
, pBrush
);
1288 HighlightRange(pDC
, ftd
, todate
, pPen
, pBrush
);
1293 wxPoint corners
[8]; // potentially 8 corners in polygon
1297 // simple case: same week
1299 corners
[0] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
);
1300 corners
[1] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1 ) * m_heightRow
) + m_rowOffset
);
1301 corners
[2] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
);
1302 corners
[3] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
);
1307 // "complex" polygon
1308 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1312 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1313 corners
[cidx
] = wxPoint(0, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1316 corners
[cidx
] = wxPoint(0, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1317 corners
[cidx
] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1321 corners
[cidx
] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1322 corners
[cidx
] = wxPoint(7 * m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1325 corners
[cidx
] = wxPoint(7 * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1331 pDC
->SetBrush(*pBrush
);
1333 pDC
->DrawPolygon(numpoints
, corners
);
1339 wxLogDebug("--- HighlightRange ---");
1343 bool wxCalendarCtrl::GetDateCoord(const wxDateTime
& date
, int *day
, int *week
) const
1348 wxLogDebug("+++ GetDateCoord: (%s) +++", date
.Format("%d %m %Y"));
1351 if ( IsDateShown(date
) )
1353 bool startOnMonday
= ( GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1356 *day
= date
.GetWeekDay();
1358 if ( *day
== 0 ) // sunday
1360 *day
= ( startOnMonday
) ? 7 : 1;
1364 *day
+= ( startOnMonday
) ? 0 : 1;
1367 int targetmonth
= date
.GetMonth() + (12 * date
.GetYear());
1368 int thismonth
= m_date
.GetMonth() + (12 * m_date
.GetYear());
1371 if ( targetmonth
== thismonth
)
1373 *week
= GetWeek(date
);
1377 if ( targetmonth
< thismonth
)
1379 *week
= 1; // trivial
1381 else // targetmonth > thismonth
1387 // get the datecoord of the last day in the month currently shown
1389 wxLogDebug(" +++ LDOM +++");
1391 GetDateCoord(ldcm
.SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear()), &lastday
, &lastweek
);
1393 wxLogDebug(" --- LDOM ---");
1396 wxTimeSpan span
= date
- ldcm
;
1398 int daysfromlast
= span
.GetDays();
1400 wxLogDebug("daysfromlast: %i", daysfromlast
);
1402 if ( daysfromlast
+ lastday
> 7 ) // past week boundary
1404 int wholeweeks
= (daysfromlast
/ 7);
1405 *week
= wholeweeks
+ lastweek
;
1406 if ( (daysfromlast
- (7 * wholeweeks
) + lastday
) > 7 )
1426 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date
.Format("%d %m %Y"), *day
, *week
);
1432 // ----------------------------------------------------------------------------
1434 // ----------------------------------------------------------------------------
1436 void wxCalendarCtrl::OnDClick(wxMouseEvent
& event
)
1438 if ( HitTest(event
.GetPosition()) != wxCAL_HITTEST_DAY
)
1444 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1448 void wxCalendarCtrl::OnClick(wxMouseEvent
& event
)
1451 wxDateTime::WeekDay wday
;
1452 switch ( HitTest(event
.GetPosition(), &date
, &wday
) )
1454 case wxCAL_HITTEST_DAY
:
1455 if ( IsDateInRange(date
) )
1459 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED
,
1460 wxEVT_CALENDAR_SEL_CHANGED
);
1464 case wxCAL_HITTEST_HEADER
:
1466 wxCalendarEvent
event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED
);
1467 event
.m_wday
= wday
;
1468 (void)GetEventHandler()->ProcessEvent(event
);
1472 case wxCAL_HITTEST_DECMONTH
:
1473 case wxCAL_HITTEST_INCMONTH
:
1474 case wxCAL_HITTEST_SURROUNDING_WEEK
:
1475 SetDateAndNotify(date
); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1479 wxFAIL_MSG(_T("unknown hittest code"));
1482 case wxCAL_HITTEST_NOWHERE
:
1488 wxCalendarHitTestResult
wxCalendarCtrl::HitTest(const wxPoint
& pos
,
1490 wxDateTime::WeekDay
*wd
)
1496 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1497 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
1501 // we need to find out if the hit is on left arrow, on month or on right arrow
1503 if ( wxRegion(m_leftArrowRect
).Contains(pos
) == wxInRegion
)
1507 if ( IsDateInRange(m_date
- wxDateSpan::Month()) )
1509 *date
= m_date
- wxDateSpan::Month();
1513 *date
= GetLowerDateLimit();
1517 return wxCAL_HITTEST_DECMONTH
;
1520 if ( wxRegion(m_rightArrowRect
).Contains(pos
) == wxInRegion
)
1524 if ( IsDateInRange(m_date
+ wxDateSpan::Month()) )
1526 *date
= m_date
+ wxDateSpan::Month();
1530 *date
= GetUpperDateLimit();
1534 return wxCAL_HITTEST_INCMONTH
;
1539 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1541 int wday
= pos
.x
/ m_widthCol
;
1542 // if ( y < m_heightRow )
1543 if ( y
< (m_heightRow
+ m_rowOffset
) )
1545 if ( y
> m_rowOffset
)
1549 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST
)
1551 wday
= wday
== 6 ? 0 : wday
+ 1;
1554 *wd
= (wxDateTime::WeekDay
)wday
;
1557 return wxCAL_HITTEST_HEADER
;
1561 return wxCAL_HITTEST_NOWHERE
;
1565 // int week = (y - m_heightRow) / m_heightRow;
1566 int week
= (y
- (m_heightRow
+ m_rowOffset
)) / m_heightRow
;
1567 if ( week
>= 6 || wday
>= 7 )
1569 return wxCAL_HITTEST_NOWHERE
;
1572 wxDateTime dt
= GetStartDate() + wxDateSpan::Days(7*week
+ wday
);
1574 if ( IsDateShown(dt
) )
1579 if ( dt
.GetMonth() == m_date
.GetMonth() )
1582 return wxCAL_HITTEST_DAY
;
1586 return wxCAL_HITTEST_SURROUNDING_WEEK
;
1591 return wxCAL_HITTEST_NOWHERE
;
1595 // ----------------------------------------------------------------------------
1596 // subcontrols events handling
1597 // ----------------------------------------------------------------------------
1599 void wxCalendarCtrl::OnMonthChange(wxCommandEvent
& event
)
1601 wxDateTime::Tm tm
= m_date
.GetTm();
1603 wxDateTime::Month mon
= (wxDateTime::Month
)event
.GetInt();
1604 if ( tm
.mday
> wxDateTime::GetNumberOfDays(mon
, tm
.year
) )
1606 tm
.mday
= wxDateTime::GetNumberOfDays(mon
, tm
.year
);
1609 wxDateTime target
= wxDateTime(tm
.mday
, mon
, tm
.year
);
1611 ChangeMonth(&target
);
1612 SetDateAndNotify(target
);
1615 void wxCalendarCtrl::OnYearChange(wxCommandEvent
& event
)
1617 int year
= (int)event
.GetInt();
1618 if ( year
== INT_MIN
)
1620 // invalid year in the spin control, ignore it
1624 wxDateTime::Tm tm
= m_date
.GetTm();
1626 if ( tm
.mday
> wxDateTime::GetNumberOfDays(tm
.mon
, year
) )
1628 tm
.mday
= wxDateTime::GetNumberOfDays(tm
.mon
, year
);
1631 wxDateTime target
= wxDateTime(tm
.mday
, tm
.mon
, year
);
1633 if ( ChangeYear(&target
) )
1635 SetDateAndNotify(target
);
1639 // In this case we don't want to change the date. That would put us
1640 // inside the same year but a strange number of months forward/back..
1641 m_spinYear
->SetValue(target
.GetYear());
1645 // ----------------------------------------------------------------------------
1646 // keyboard interface
1647 // ----------------------------------------------------------------------------
1649 void wxCalendarCtrl::OnChar(wxKeyEvent
& event
)
1652 switch ( event
.GetKeyCode() )
1656 target
= m_date
+ wxDateSpan::Year();
1657 if ( ChangeYear(&target
) )
1659 SetDateAndNotify(target
);
1665 target
= m_date
- wxDateSpan::Year();
1666 if ( ChangeYear(&target
) )
1668 SetDateAndNotify(target
);
1673 target
= m_date
- wxDateSpan::Month();
1674 ChangeMonth(&target
);
1675 SetDateAndNotify(target
); // always
1679 target
= m_date
+ wxDateSpan::Month();
1680 ChangeMonth(&target
);
1681 SetDateAndNotify(target
); // always
1685 if ( event
.ControlDown() )
1687 target
= wxDateTime(m_date
).SetToNextWeekDay(
1688 GetWindowStyle() & wxCAL_MONDAY_FIRST
1689 ? wxDateTime::Sun
: wxDateTime::Sat
);
1690 if ( !IsDateInRange(target
) )
1692 target
= GetUpperDateLimit();
1694 SetDateAndNotify(target
);
1697 SetDateAndNotify(m_date
+ wxDateSpan::Day());
1701 if ( event
.ControlDown() )
1703 target
= wxDateTime(m_date
).SetToPrevWeekDay(
1704 GetWindowStyle() & wxCAL_MONDAY_FIRST
1705 ? wxDateTime::Mon
: wxDateTime::Sun
);
1706 if ( !IsDateInRange(target
) )
1708 target
= GetLowerDateLimit();
1710 SetDateAndNotify(target
);
1713 SetDateAndNotify(m_date
- wxDateSpan::Day());
1717 SetDateAndNotify(m_date
- wxDateSpan::Week());
1721 SetDateAndNotify(m_date
+ wxDateSpan::Week());
1725 if ( event
.ControlDown() )
1726 SetDateAndNotify(wxDateTime::Today());
1728 SetDateAndNotify(wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear()));
1732 SetDateAndNotify(wxDateTime(m_date
).SetToLastMonthDay());
1736 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1744 // ----------------------------------------------------------------------------
1745 // holidays handling
1746 // ----------------------------------------------------------------------------
1748 void wxCalendarCtrl::EnableHolidayDisplay(bool display
)
1750 long style
= GetWindowStyle();
1752 style
|= wxCAL_SHOW_HOLIDAYS
;
1754 style
&= ~wxCAL_SHOW_HOLIDAYS
;
1756 SetWindowStyle(style
);
1761 ResetHolidayAttrs();
1766 void wxCalendarCtrl::SetHolidayAttrs()
1768 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS
)
1770 ResetHolidayAttrs();
1772 wxDateTime::Tm tm
= m_date
.GetTm();
1773 wxDateTime
dtStart(1, tm
.mon
, tm
.year
),
1774 dtEnd
= dtStart
.GetLastMonthDay();
1776 wxDateTimeArray hol
;
1777 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart
, dtEnd
, hol
);
1779 size_t count
= hol
.GetCount();
1780 for ( size_t n
= 0; n
< count
; n
++ )
1782 SetHoliday(hol
[n
].GetDay());
1787 void wxCalendarCtrl::SetHoliday(size_t day
)
1789 wxCHECK_RET( day
> 0 && day
< 32, _T("invalid day in SetHoliday") );
1791 wxCalendarDateAttr
*attr
= GetAttr(day
);
1794 attr
= new wxCalendarDateAttr
;
1797 attr
->SetHoliday(true);
1799 // can't use SetAttr() because it would delete this pointer
1800 m_attrs
[day
- 1] = attr
;
1803 void wxCalendarCtrl::ResetHolidayAttrs()
1805 for ( size_t day
= 0; day
< 31; day
++ )
1809 m_attrs
[day
]->SetHoliday(false);
1817 wxCalendarCtrl::GetClassDefaultAttributes(wxWindowVariant variant
)
1819 // Use the same color scheme as wxListBox
1820 return wxListBox::GetClassDefaultAttributes(variant
);
1824 // ----------------------------------------------------------------------------
1826 // ----------------------------------------------------------------------------
1828 void wxCalendarEvent::Init()
1830 m_wday
= wxDateTime::Inv_WeekDay
;
1833 wxCalendarEvent::wxCalendarEvent(wxCalendarCtrl
*cal
, wxEventType type
)
1834 : wxCommandEvent(type
, cal
->GetId())
1836 m_date
= cal
->GetDate();
1837 SetEventObject(cal
);
1840 #endif // wxUSE_CALENDARCTRL