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"
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(wxDefaultPosition
.x
,
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
321 wxCalendarCtrl::~wxCalendarCtrl()
323 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
329 // ----------------------------------------------------------------------------
330 // forward wxWin functions to subcontrols
331 // ----------------------------------------------------------------------------
333 bool wxCalendarCtrl::Destroy()
336 m_staticYear
->Destroy();
338 m_spinYear
->Destroy();
340 m_comboMonth
->Destroy();
342 m_staticMonth
->Destroy();
347 m_staticMonth
= NULL
;
349 return wxControl::Destroy();
352 bool wxCalendarCtrl::Show(bool show
)
354 if ( !wxControl::Show(show
) )
359 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
361 if ( GetMonthControl() )
363 GetMonthControl()->Show(show
);
364 GetYearControl()->Show(show
);
371 bool wxCalendarCtrl::Enable(bool enable
)
373 if ( !wxControl::Enable(enable
) )
378 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
380 GetMonthControl()->Enable(enable
);
381 GetYearControl()->Enable(enable
);
387 // ----------------------------------------------------------------------------
388 // enable/disable month/year controls
389 // ----------------------------------------------------------------------------
391 void wxCalendarCtrl::ShowCurrentControls()
393 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
395 if ( AllowMonthChange() )
397 m_comboMonth
->Show();
398 m_staticMonth
->Hide();
400 if ( AllowYearChange() )
403 m_staticYear
->Hide();
411 m_comboMonth
->Hide();
412 m_staticMonth
->Show();
415 // year change not allowed here
417 m_staticYear
->Show();
421 wxControl
*wxCalendarCtrl::GetMonthControl() const
423 return AllowMonthChange() ? (wxControl
*)m_comboMonth
: (wxControl
*)m_staticMonth
;
426 wxControl
*wxCalendarCtrl::GetYearControl() const
428 return AllowYearChange() ? (wxControl
*)m_spinYear
: (wxControl
*)m_staticYear
;
431 void wxCalendarCtrl::EnableYearChange(bool enable
)
433 if ( enable
!= AllowYearChange() )
435 long style
= GetWindowStyle();
437 style
&= ~wxCAL_NO_YEAR_CHANGE
;
439 style
|= wxCAL_NO_YEAR_CHANGE
;
440 SetWindowStyle(style
);
442 ShowCurrentControls();
443 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
450 void wxCalendarCtrl::EnableMonthChange(bool enable
)
452 if ( enable
!= AllowMonthChange() )
454 long style
= GetWindowStyle();
456 style
&= ~wxCAL_NO_MONTH_CHANGE
;
458 style
|= wxCAL_NO_MONTH_CHANGE
;
459 SetWindowStyle(style
);
461 ShowCurrentControls();
462 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
469 // ----------------------------------------------------------------------------
471 // ----------------------------------------------------------------------------
473 bool wxCalendarCtrl::SetDate(const wxDateTime
& date
)
477 bool sameMonth
= m_date
.GetMonth() == date
.GetMonth(),
478 sameYear
= m_date
.GetYear() == date
.GetYear();
480 if ( IsDateInRange(date
) )
482 if ( sameMonth
&& sameYear
)
484 // just change the day
489 if ( AllowMonthChange() && (AllowYearChange() || sameYear
) )
494 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
496 // update the controls
497 m_comboMonth
->SetSelection(m_date
.GetMonth());
499 if ( AllowYearChange() )
501 if ( !m_userChangedYear
)
502 m_spinYear
->SetValue(m_date
.Format(_T("%Y")));
506 // as the month changed, holidays did too
509 // update the calendar
520 m_userChangedYear
= false;
525 void wxCalendarCtrl::ChangeDay(const wxDateTime
& date
)
527 if ( m_date
!= date
)
529 // we need to refresh the row containing the old date and the one
530 // containing the new one
531 wxDateTime dateOld
= m_date
;
534 RefreshDate(dateOld
);
536 // if the date is in the same row, it was already drawn correctly
537 if ( GetWeek(m_date
) != GetWeek(dateOld
) )
544 void wxCalendarCtrl::SetDateAndNotify(const wxDateTime
& date
)
546 wxDateTime::Tm tm1
= m_date
.GetTm(),
550 if ( tm1
.year
!= tm2
.year
)
551 type
= wxEVT_CALENDAR_YEAR_CHANGED
;
552 else if ( tm1
.mon
!= tm2
.mon
)
553 type
= wxEVT_CALENDAR_MONTH_CHANGED
;
554 else if ( tm1
.mday
!= tm2
.mday
)
555 type
= wxEVT_CALENDAR_DAY_CHANGED
;
561 GenerateEvents(type
, wxEVT_CALENDAR_SEL_CHANGED
);
565 // ----------------------------------------------------------------------------
567 // ----------------------------------------------------------------------------
569 bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
573 if ( !(date
.IsValid()) || ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) )
585 bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
589 if ( !(date
.IsValid()) || ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true ) )
601 bool wxCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
/* = wxDefaultDateTime */, const wxDateTime
& upperdate
/* = wxDefaultDateTime */)
606 ( !( lowerdate
.IsValid() ) || ( ( upperdate
.IsValid() ) ? ( lowerdate
<= upperdate
) : true ) ) &&
607 ( !( upperdate
.IsValid() ) || ( ( lowerdate
.IsValid() ) ? ( upperdate
>= lowerdate
) : true ) ) )
609 m_lowdate
= lowerdate
;
610 m_highdate
= upperdate
;
620 // ----------------------------------------------------------------------------
622 // ----------------------------------------------------------------------------
624 wxDateTime
wxCalendarCtrl::GetStartDate() const
626 wxDateTime::Tm tm
= m_date
.GetTm();
628 wxDateTime date
= wxDateTime(1, tm
.mon
, tm
.year
);
631 date
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
632 ? wxDateTime::Mon
: wxDateTime::Sun
);
634 if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
)
636 // We want to offset the calendar if we start on the first..
637 if ( date
.GetDay() == 1 )
639 date
-= wxDateSpan::Week();
646 bool wxCalendarCtrl::IsDateShown(const wxDateTime
& date
) const
648 if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
650 return date
.GetMonth() == m_date
.GetMonth();
658 bool wxCalendarCtrl::IsDateInRange(const wxDateTime
& date
) const
660 // Check if the given date is in the range specified
661 return ( ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true )
662 && ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) );
665 bool wxCalendarCtrl::ChangeYear(wxDateTime
* target
) const
669 if ( !(IsDateInRange(*target
)) )
671 if ( target
->GetYear() < m_date
.GetYear() )
673 if ( target
->GetYear() >= GetLowerDateLimit().GetYear() )
675 *target
= GetLowerDateLimit();
685 if ( target
->GetYear() <= GetUpperDateLimit().GetYear() )
687 *target
= GetUpperDateLimit();
704 bool wxCalendarCtrl::ChangeMonth(wxDateTime
* target
) const
708 if ( !(IsDateInRange(*target
)) )
712 if ( target
->GetMonth() < m_date
.GetMonth() )
714 *target
= GetLowerDateLimit();
718 *target
= GetUpperDateLimit();
725 size_t wxCalendarCtrl::GetWeek(const wxDateTime
& date
) const
727 size_t retval
= date
.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
728 ? wxDateTime::Monday_First
729 : wxDateTime::Sunday_First
);
731 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
733 // we need to offset an extra week if we "start" on the 1st of the month
734 wxDateTime::Tm tm
= date
.GetTm();
736 wxDateTime datetest
= wxDateTime(1, tm
.mon
, tm
.year
);
739 datetest
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
740 ? wxDateTime::Mon
: wxDateTime::Sun
);
742 if ( datetest
.GetDay() == 1 )
751 // ----------------------------------------------------------------------------
753 // ----------------------------------------------------------------------------
755 // this is a composite control and it must arrange its parts each time its
756 // size or position changes: the combobox and spinctrl are along the top of
757 // the available area and the calendar takes up therest of the space
759 // the static controls are supposed to be always smaller than combo/spin so we
760 // always use the latter for size calculations and position the static to take
763 // the constants used for the layout
764 #define VERT_MARGIN 5 // distance between combo and calendar
766 #define HORZ_MARGIN 5 // spin
768 #define HORZ_MARGIN 15 // spin
770 wxSize
wxCalendarCtrl::DoGetBestSize() const
772 // calc the size of the calendar
773 ((wxCalendarCtrl
*)this)->RecalcGeometry(); // const_cast
775 wxCoord width
= 7*m_widthCol
,
776 height
= 7*m_heightRow
+ m_rowOffset
+ VERT_MARGIN
;
778 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
780 // the combobox doesn't report its height correctly (it returns the
781 // height including the drop down list) so don't use it
782 height
+= m_spinYear
->GetBestSize().y
;
785 if ( !HasFlag(wxBORDER_NONE
) )
787 // the border would clip the last line otherwise
792 wxSize
best(width
, height
);
797 void wxCalendarCtrl::DoSetSize(int x
, int y
,
798 int width
, int height
,
801 wxControl::DoSetSize(x
, y
, width
, height
, sizeFlags
);
804 void wxCalendarCtrl::DoMoveWindow(int x
, int y
, int width
, int height
)
808 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
810 wxSize sizeCombo
= m_comboMonth
->GetSize();
811 wxSize sizeStatic
= m_staticMonth
->GetSize();
812 wxSize sizeSpin
= m_spinYear
->GetSize();
813 int dy
= (sizeCombo
.y
- sizeStatic
.y
) / 2;
815 In the calender the size of the combobox for the year
816 is just defined by a margin from the month combobox to
817 the left border. While in wxUniv the year control can't
818 show all 4 digits, in wxMsw it show almost twice as
819 much. Instead the year should use it's best size and be
820 left aligned to the calendar. Just in case the month in
821 any language is longer than it has space in the
822 calendar it is shortend.This way the year always can
825 This patch relies on the fact that a combobox has a
826 good best size implementation. This is not the case
827 with wxMSW but I don't know why.
832 #ifdef __WXUNIVERSAL__
833 if (sizeCombo
.x
+ HORZ_MARGIN
- sizeSpin
.x
> width
)
835 m_comboMonth
->SetSize(x
, y
, width
- HORZ_MARGIN
- sizeSpin
.x
, sizeCombo
.y
);
839 m_comboMonth
->Move(x
, y
);
841 m_staticMonth
->Move(x
, y
+ dy
);
842 m_spinYear
->Move(x
+ width
- sizeSpin
.x
, y
);
843 m_staticYear
->Move(x
+ width
- sizeSpin
.x
, y
+ dy
);
845 m_comboMonth
->Move(x
, y
);
846 m_staticMonth
->SetSize(x
, y
+ dy
, sizeCombo
.x
, sizeStatic
.y
);
848 int xDiff
= sizeCombo
.x
+ HORZ_MARGIN
;
850 m_spinYear
->SetSize(x
+ xDiff
, y
, width
- xDiff
, sizeCombo
.y
);
851 m_staticYear
->SetSize(x
+ xDiff
, y
+ dy
, width
- xDiff
, sizeStatic
.y
);
853 yDiff
= wxMax(sizeSpin
.y
, sizeCombo
.y
) + VERT_MARGIN
;
855 else // no controls on the top
860 wxControl::DoMoveWindow(x
, y
+ yDiff
, width
, height
- yDiff
);
863 void wxCalendarCtrl::DoGetPosition(int *x
, int *y
) const
865 wxControl::DoGetPosition(x
, y
);
867 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
869 // our real top corner is not in this position
872 *y
-= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
877 void wxCalendarCtrl::DoGetSize(int *width
, int *height
) const
879 wxControl::DoGetSize(width
, height
);
881 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
883 // our real height is bigger
884 if ( height
&& GetMonthControl())
886 *height
+= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
891 void wxCalendarCtrl::RecalcGeometry()
895 dc
.SetFont(GetFont());
897 // determine the column width (we assume that the weekday names are always
898 // wider (in any language) than the numbers)
900 wxDateTime::WeekDay wd
;
901 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
904 dc
.GetTextExtent(m_weekdays
[wd
], &width
, &m_heightRow
);
905 if ( width
> m_widthCol
)
911 // leave some margins
915 m_rowOffset
= (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) ? m_heightRow
: 0; // conditional in relation to style
918 // ----------------------------------------------------------------------------
920 // ----------------------------------------------------------------------------
922 void wxCalendarCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
))
926 dc
.SetFont(GetFont());
931 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
932 m_date
.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
938 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
940 // draw the sequential month-selector
942 dc
.SetBackgroundMode(wxTRANSPARENT
);
943 dc
.SetTextForeground(*wxBLACK
);
944 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
945 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
946 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
948 // Get extent of month-name + year
949 wxCoord monthw
, monthh
;
950 wxString headertext
= m_date
.Format(wxT("%B %Y"));
951 dc
.GetTextExtent(headertext
, &monthw
, &monthh
);
953 // draw month-name centered above weekdays
954 wxCoord monthx
= ((m_widthCol
* 7) - monthw
) / 2;
955 wxCoord monthy
= ((m_heightRow
- monthh
) / 2) + y
;
956 dc
.DrawText(headertext
, monthx
, monthy
);
958 // calculate the "month-arrows"
959 wxPoint leftarrow
[3];
960 wxPoint rightarrow
[3];
962 int arrowheight
= monthh
/ 2;
964 leftarrow
[0] = wxPoint(0, arrowheight
/ 2);
965 leftarrow
[1] = wxPoint(arrowheight
/ 2, 0);
966 leftarrow
[2] = wxPoint(arrowheight
/ 2, arrowheight
- 1);
968 rightarrow
[0] = wxPoint(0, 0);
969 rightarrow
[1] = wxPoint(arrowheight
/ 2, arrowheight
/ 2);
970 rightarrow
[2] = wxPoint(0, arrowheight
- 1);
972 // draw the "month-arrows"
974 wxCoord arrowy
= (m_heightRow
- arrowheight
) / 2;
975 wxCoord larrowx
= (m_widthCol
- (arrowheight
/ 2)) / 2;
976 wxCoord rarrowx
= ((m_widthCol
- (arrowheight
/ 2)) / 2) + m_widthCol
*6;
977 m_leftArrowRect
= wxRect(0, 0, 0, 0);
978 m_rightArrowRect
= wxRect(0, 0, 0, 0);
980 if ( AllowMonthChange() )
982 wxDateTime ldpm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) - wxDateSpan::Day(); // last day prev month
983 // Check if range permits change
984 if ( IsDateInRange(ldpm
) && ( ( ldpm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
986 m_leftArrowRect
= wxRect(larrowx
- 3, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
987 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
988 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
989 dc
.DrawPolygon(3, leftarrow
, larrowx
, arrowy
, wxWINDING_RULE
);
990 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
991 dc
.DrawRectangle(m_leftArrowRect
);
993 wxDateTime fdnm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) + wxDateSpan::Month(); // first day next month
994 if ( IsDateInRange(fdnm
) && ( ( fdnm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
996 m_rightArrowRect
= wxRect(rarrowx
- 4, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
997 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
998 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
999 dc
.DrawPolygon(3, rightarrow
, rarrowx
, arrowy
, wxWINDING_RULE
);
1000 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1001 dc
.DrawRectangle(m_rightArrowRect
);
1008 // first draw the week days
1009 if ( IsExposed(0, y
, 7*m_widthCol
, m_heightRow
) )
1012 wxLogDebug("painting the header");
1015 dc
.SetBackgroundMode(wxTRANSPARENT
);
1016 dc
.SetTextForeground(m_colHeaderFg
);
1017 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
1018 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
1019 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
1021 bool startOnMonday
= (GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1022 for ( size_t wd
= 0; wd
< 7; wd
++ )
1025 if ( startOnMonday
)
1026 n
= wd
== 6 ? 0 : wd
+ 1;
1030 dc
.GetTextExtent(m_weekdays
[n
], &dayw
, &dayh
);
1031 dc
.DrawText(m_weekdays
[n
], (wd
*m_widthCol
) + ((m_widthCol
- dayw
) / 2), y
); // center the day-name
1035 // then the calendar itself
1036 dc
.SetTextForeground(*wxBLACK
);
1037 //dc.SetFont(*wxNORMAL_FONT);
1040 wxDateTime date
= GetStartDate();
1043 wxLogDebug("starting calendar from %s\n",
1044 date
.Format("%a %d-%m-%Y %H:%M:%S").c_str());
1047 dc
.SetBackgroundMode(wxSOLID
);
1048 for ( size_t nWeek
= 1; nWeek
<= 6; nWeek
++, y
+= m_heightRow
)
1050 // if the update region doesn't intersect this row, don't paint it
1051 if ( !IsExposed(0, y
, 7*m_widthCol
, m_heightRow
- 1) )
1053 date
+= wxDateSpan::Week();
1059 wxLogDebug("painting week %d at y = %d\n", nWeek
, y
);
1062 for ( size_t wd
= 0; wd
< 7; wd
++ )
1064 if ( IsDateShown(date
) )
1066 // don't use wxDate::Format() which prepends 0s
1067 unsigned int day
= date
.GetDay();
1068 wxString dayStr
= wxString::Format(_T("%u"), day
);
1070 dc
.GetTextExtent(dayStr
, &width
, (wxCoord
*)NULL
);
1072 bool changedColours
= false,
1073 changedFont
= false;
1076 wxCalendarDateAttr
*attr
= NULL
;
1078 if ( date
.GetMonth() != m_date
.GetMonth() || !IsDateInRange(date
) )
1080 // surrounding week or out-of-range
1082 dc
.SetTextForeground(*wxLIGHT_GREY
);
1083 changedColours
= true;
1087 isSel
= date
.IsSameDate(m_date
);
1088 attr
= m_attrs
[day
- 1];
1092 dc
.SetTextForeground(m_colHighlightFg
);
1093 dc
.SetTextBackground(m_colHighlightBg
);
1095 changedColours
= true;
1099 wxColour colFg
, colBg
;
1101 if ( attr
->IsHoliday() )
1103 colFg
= m_colHolidayFg
;
1104 colBg
= m_colHolidayBg
;
1108 colFg
= attr
->GetTextColour();
1109 colBg
= attr
->GetBackgroundColour();
1114 dc
.SetTextForeground(colFg
);
1115 changedColours
= true;
1120 dc
.SetTextBackground(colBg
);
1121 changedColours
= true;
1124 if ( attr
->HasFont() )
1126 dc
.SetFont(attr
->GetFont());
1132 wxCoord x
= wd
*m_widthCol
+ (m_widthCol
- width
) / 2;
1133 dc
.DrawText(dayStr
, x
, y
+ 1);
1135 if ( !isSel
&& attr
&& attr
->HasBorder() )
1138 if ( attr
->HasBorderColour() )
1140 colBorder
= attr
->GetBorderColour();
1144 colBorder
= GetForegroundColour();
1147 wxPen
pen(colBorder
, 1, wxSOLID
);
1149 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1151 switch ( attr
->GetBorder() )
1153 case wxCAL_BORDER_SQUARE
:
1154 dc
.DrawRectangle(x
- 2, y
,
1155 width
+ 4, m_heightRow
);
1158 case wxCAL_BORDER_ROUND
:
1159 dc
.DrawEllipse(x
- 2, y
,
1160 width
+ 4, m_heightRow
);
1164 wxFAIL_MSG(_T("unknown border type"));
1168 if ( changedColours
)
1170 dc
.SetTextForeground(GetForegroundColour());
1171 dc
.SetTextBackground(GetBackgroundColour());
1176 dc
.SetFont(GetFont());
1179 //else: just don't draw it
1181 date
+= wxDateSpan::Day();
1185 // Greying out out-of-range background
1186 bool showSurrounding
= (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) != 0;
1188 date
= ( showSurrounding
) ? GetStartDate() : wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear());
1189 if ( !IsDateInRange(date
) )
1191 wxDateTime firstOOR
= GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1193 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1194 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1196 HighlightRange(&dc
, date
, firstOOR
, wxTRANSPARENT_PEN
, &oorbrush
);
1199 date
= ( showSurrounding
) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear());
1200 if ( !IsDateInRange(date
) )
1202 wxDateTime firstOOR
= GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1204 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1205 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1207 HighlightRange(&dc
, firstOOR
, date
, wxTRANSPARENT_PEN
, &oorbrush
);
1211 wxLogDebug("+++ finished painting");
1215 void wxCalendarCtrl::RefreshDate(const wxDateTime
& date
)
1221 // always refresh the whole row at once because our OnPaint() will draw
1222 // the whole row anyhow - and this allows the small optimisation in
1223 // OnClick() below to work
1226 rect
.y
= (m_heightRow
* GetWeek(date
)) + m_rowOffset
;
1228 rect
.width
= 7*m_widthCol
;
1229 rect
.height
= m_heightRow
;
1232 // VZ: for some reason, the selected date seems to occupy more space under
1233 // MSW - this is probably some bug in the font size calculations, but I
1234 // don't know where exactly. This fix is ugly and leads to more
1235 // refreshes than really needed, but without it the selected days
1236 // leaves even more ugly underscores on screen.
1241 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
1244 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
1247 Refresh(true, &rect
);
1250 void wxCalendarCtrl::HighlightRange(wxPaintDC
* pDC
, const wxDateTime
& fromdate
, const wxDateTime
& todate
, wxPen
* pPen
, wxBrush
* pBrush
)
1252 // Highlights the given range using pen and brush
1253 // Does nothing if todate < fromdate
1257 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate
.Format("%d %m %Y"), todate
.Format("%d %m %Y"));
1260 if ( todate
>= fromdate
)
1267 // implicit: both dates must be currently shown - checked by GetDateCoord
1268 if ( GetDateCoord(fromdate
, &fd
, &fw
) && GetDateCoord(todate
, &td
, &tw
) )
1271 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd
, fw
, td
, tw
);
1273 if ( ( (tw
- fw
) == 1 ) && ( td
< fd
) )
1275 // special case: interval 7 days or less not in same week
1276 // split in two seperate intervals
1277 wxDateTime tfd
= fromdate
+ wxDateSpan::Days(7-fd
);
1278 wxDateTime ftd
= tfd
+ wxDateSpan::Day();
1280 wxLogDebug("Highlight: Seperate segments");
1283 HighlightRange(pDC
, fromdate
, tfd
, pPen
, pBrush
);
1284 HighlightRange(pDC
, ftd
, todate
, pPen
, pBrush
);
1289 wxPoint corners
[8]; // potentially 8 corners in polygon
1293 // simple case: same week
1295 corners
[0] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
);
1296 corners
[1] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1 ) * m_heightRow
) + m_rowOffset
);
1297 corners
[2] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
);
1298 corners
[3] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
);
1303 // "complex" polygon
1304 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1308 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1309 corners
[cidx
] = wxPoint(0, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1312 corners
[cidx
] = wxPoint(0, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1313 corners
[cidx
] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1317 corners
[cidx
] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1318 corners
[cidx
] = wxPoint(7 * m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1321 corners
[cidx
] = wxPoint(7 * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1327 pDC
->SetBrush(*pBrush
);
1329 pDC
->DrawPolygon(numpoints
, corners
);
1335 wxLogDebug("--- HighlightRange ---");
1339 bool wxCalendarCtrl::GetDateCoord(const wxDateTime
& date
, int *day
, int *week
) const
1344 wxLogDebug("+++ GetDateCoord: (%s) +++", date
.Format("%d %m %Y"));
1347 if ( IsDateShown(date
) )
1349 bool startOnMonday
= ( GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1352 *day
= date
.GetWeekDay();
1354 if ( *day
== 0 ) // sunday
1356 *day
= ( startOnMonday
) ? 7 : 1;
1360 *day
+= ( startOnMonday
) ? 0 : 1;
1363 int targetmonth
= date
.GetMonth() + (12 * date
.GetYear());
1364 int thismonth
= m_date
.GetMonth() + (12 * m_date
.GetYear());
1367 if ( targetmonth
== thismonth
)
1369 *week
= GetWeek(date
);
1373 if ( targetmonth
< thismonth
)
1375 *week
= 1; // trivial
1377 else // targetmonth > thismonth
1383 // get the datecoord of the last day in the month currently shown
1385 wxLogDebug(" +++ LDOM +++");
1387 GetDateCoord(ldcm
.SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear()), &lastday
, &lastweek
);
1389 wxLogDebug(" --- LDOM ---");
1392 wxTimeSpan span
= date
- ldcm
;
1394 int daysfromlast
= span
.GetDays();
1396 wxLogDebug("daysfromlast: %i", daysfromlast
);
1398 if ( daysfromlast
+ lastday
> 7 ) // past week boundary
1400 int wholeweeks
= (daysfromlast
/ 7);
1401 *week
= wholeweeks
+ lastweek
;
1402 if ( (daysfromlast
- (7 * wholeweeks
) + lastday
) > 7 )
1422 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date
.Format("%d %m %Y"), *day
, *week
);
1428 // ----------------------------------------------------------------------------
1430 // ----------------------------------------------------------------------------
1432 void wxCalendarCtrl::OnDClick(wxMouseEvent
& event
)
1434 if ( HitTest(event
.GetPosition()) != wxCAL_HITTEST_DAY
)
1440 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1444 void wxCalendarCtrl::OnClick(wxMouseEvent
& event
)
1447 wxDateTime::WeekDay wday
;
1448 switch ( HitTest(event
.GetPosition(), &date
, &wday
) )
1450 case wxCAL_HITTEST_DAY
:
1451 if ( IsDateInRange(date
) )
1455 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED
,
1456 wxEVT_CALENDAR_SEL_CHANGED
);
1460 case wxCAL_HITTEST_HEADER
:
1462 wxCalendarEvent
event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED
);
1463 event
.m_wday
= wday
;
1464 (void)GetEventHandler()->ProcessEvent(event
);
1468 case wxCAL_HITTEST_DECMONTH
:
1469 case wxCAL_HITTEST_INCMONTH
:
1470 case wxCAL_HITTEST_SURROUNDING_WEEK
:
1471 SetDateAndNotify(date
); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1475 wxFAIL_MSG(_T("unknown hittest code"));
1478 case wxCAL_HITTEST_NOWHERE
:
1484 wxCalendarHitTestResult
wxCalendarCtrl::HitTest(const wxPoint
& pos
,
1486 wxDateTime::WeekDay
*wd
)
1492 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1493 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
1497 // we need to find out if the hit is on left arrow, on month or on right arrow
1499 if ( wxRegion(m_leftArrowRect
).Contains(pos
) == wxInRegion
)
1503 if ( IsDateInRange(m_date
- wxDateSpan::Month()) )
1505 *date
= m_date
- wxDateSpan::Month();
1509 *date
= GetLowerDateLimit();
1513 return wxCAL_HITTEST_DECMONTH
;
1516 if ( wxRegion(m_rightArrowRect
).Contains(pos
) == wxInRegion
)
1520 if ( IsDateInRange(m_date
+ wxDateSpan::Month()) )
1522 *date
= m_date
+ wxDateSpan::Month();
1526 *date
= GetUpperDateLimit();
1530 return wxCAL_HITTEST_INCMONTH
;
1535 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1537 int wday
= pos
.x
/ m_widthCol
;
1538 // if ( y < m_heightRow )
1539 if ( y
< (m_heightRow
+ m_rowOffset
) )
1541 if ( y
> m_rowOffset
)
1545 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST
)
1547 wday
= wday
== 6 ? 0 : wday
+ 1;
1550 *wd
= (wxDateTime::WeekDay
)wday
;
1553 return wxCAL_HITTEST_HEADER
;
1557 return wxCAL_HITTEST_NOWHERE
;
1561 // int week = (y - m_heightRow) / m_heightRow;
1562 int week
= (y
- (m_heightRow
+ m_rowOffset
)) / m_heightRow
;
1563 if ( week
>= 6 || wday
>= 7 )
1565 return wxCAL_HITTEST_NOWHERE
;
1568 wxDateTime dt
= GetStartDate() + wxDateSpan::Days(7*week
+ wday
);
1570 if ( IsDateShown(dt
) )
1575 if ( dt
.GetMonth() == m_date
.GetMonth() )
1578 return wxCAL_HITTEST_DAY
;
1582 return wxCAL_HITTEST_SURROUNDING_WEEK
;
1587 return wxCAL_HITTEST_NOWHERE
;
1591 // ----------------------------------------------------------------------------
1592 // subcontrols events handling
1593 // ----------------------------------------------------------------------------
1595 void wxCalendarCtrl::OnMonthChange(wxCommandEvent
& event
)
1597 wxDateTime::Tm tm
= m_date
.GetTm();
1599 wxDateTime::Month mon
= (wxDateTime::Month
)event
.GetInt();
1600 if ( tm
.mday
> wxDateTime::GetNumberOfDays(mon
, tm
.year
) )
1602 tm
.mday
= wxDateTime::GetNumberOfDays(mon
, tm
.year
);
1605 wxDateTime target
= wxDateTime(tm
.mday
, mon
, tm
.year
);
1607 ChangeMonth(&target
);
1608 SetDateAndNotify(target
);
1611 void wxCalendarCtrl::OnYearChange(wxCommandEvent
& event
)
1613 int year
= (int)event
.GetInt();
1614 if ( year
== INT_MIN
)
1616 // invalid year in the spin control, ignore it
1620 wxDateTime::Tm tm
= m_date
.GetTm();
1622 if ( tm
.mday
> wxDateTime::GetNumberOfDays(tm
.mon
, year
) )
1624 tm
.mday
= wxDateTime::GetNumberOfDays(tm
.mon
, year
);
1627 wxDateTime target
= wxDateTime(tm
.mday
, tm
.mon
, year
);
1629 if ( ChangeYear(&target
) )
1631 SetDateAndNotify(target
);
1635 // In this case we don't want to change the date. That would put us
1636 // inside the same year but a strange number of months forward/back..
1637 m_spinYear
->SetValue(target
.GetYear());
1641 // ----------------------------------------------------------------------------
1642 // keyboard interface
1643 // ----------------------------------------------------------------------------
1645 void wxCalendarCtrl::OnChar(wxKeyEvent
& event
)
1648 switch ( event
.GetKeyCode() )
1652 target
= m_date
+ wxDateSpan::Year();
1653 if ( ChangeYear(&target
) )
1655 SetDateAndNotify(target
);
1661 target
= m_date
- wxDateSpan::Year();
1662 if ( ChangeYear(&target
) )
1664 SetDateAndNotify(target
);
1669 target
= m_date
- wxDateSpan::Month();
1670 ChangeMonth(&target
);
1671 SetDateAndNotify(target
); // always
1675 target
= m_date
+ wxDateSpan::Month();
1676 ChangeMonth(&target
);
1677 SetDateAndNotify(target
); // always
1681 if ( event
.ControlDown() )
1683 target
= wxDateTime(m_date
).SetToNextWeekDay(
1684 GetWindowStyle() & wxCAL_MONDAY_FIRST
1685 ? wxDateTime::Sun
: wxDateTime::Sat
);
1686 if ( !IsDateInRange(target
) )
1688 target
= GetUpperDateLimit();
1690 SetDateAndNotify(target
);
1693 SetDateAndNotify(m_date
+ wxDateSpan::Day());
1697 if ( event
.ControlDown() )
1699 target
= wxDateTime(m_date
).SetToPrevWeekDay(
1700 GetWindowStyle() & wxCAL_MONDAY_FIRST
1701 ? wxDateTime::Mon
: wxDateTime::Sun
);
1702 if ( !IsDateInRange(target
) )
1704 target
= GetLowerDateLimit();
1706 SetDateAndNotify(target
);
1709 SetDateAndNotify(m_date
- wxDateSpan::Day());
1713 SetDateAndNotify(m_date
- wxDateSpan::Week());
1717 SetDateAndNotify(m_date
+ wxDateSpan::Week());
1721 if ( event
.ControlDown() )
1722 SetDateAndNotify(wxDateTime::Today());
1724 SetDateAndNotify(wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear()));
1728 SetDateAndNotify(wxDateTime(m_date
).SetToLastMonthDay());
1732 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1740 // ----------------------------------------------------------------------------
1741 // holidays handling
1742 // ----------------------------------------------------------------------------
1744 void wxCalendarCtrl::EnableHolidayDisplay(bool display
)
1746 long style
= GetWindowStyle();
1748 style
|= wxCAL_SHOW_HOLIDAYS
;
1750 style
&= ~wxCAL_SHOW_HOLIDAYS
;
1752 SetWindowStyle(style
);
1757 ResetHolidayAttrs();
1762 void wxCalendarCtrl::SetHolidayAttrs()
1764 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS
)
1766 ResetHolidayAttrs();
1768 wxDateTime::Tm tm
= m_date
.GetTm();
1769 wxDateTime
dtStart(1, tm
.mon
, tm
.year
),
1770 dtEnd
= dtStart
.GetLastMonthDay();
1772 wxDateTimeArray hol
;
1773 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart
, dtEnd
, hol
);
1775 size_t count
= hol
.GetCount();
1776 for ( size_t n
= 0; n
< count
; n
++ )
1778 SetHoliday(hol
[n
].GetDay());
1783 void wxCalendarCtrl::SetHoliday(size_t day
)
1785 wxCHECK_RET( day
> 0 && day
< 32, _T("invalid day in SetHoliday") );
1787 wxCalendarDateAttr
*attr
= GetAttr(day
);
1790 attr
= new wxCalendarDateAttr
;
1793 attr
->SetHoliday(true);
1795 // can't use SetAttr() because it would delete this pointer
1796 m_attrs
[day
- 1] = attr
;
1799 void wxCalendarCtrl::ResetHolidayAttrs()
1801 for ( size_t day
= 0; day
< 31; day
++ )
1805 m_attrs
[day
]->SetHoliday(false);
1813 wxCalendarCtrl::GetClassDefaultAttributes(wxWindowVariant variant
)
1815 // Use the same color scheme as wxListBox
1816 return wxListBox::GetClassDefaultAttributes(variant
);
1820 // ----------------------------------------------------------------------------
1822 // ----------------------------------------------------------------------------
1824 void wxCalendarEvent::Init()
1826 m_wday
= wxDateTime::Inv_WeekDay
;
1829 wxCalendarEvent::wxCalendarEvent(wxCalendarCtrl
*cal
, wxEventType type
)
1830 : wxCommandEvent(type
, cal
->GetId())
1832 m_date
= cal
->GetDate();
1833 SetEventObject(cal
);
1836 #endif // wxUSE_CALENDARCTRL