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 // if wxDatePickerCtrl code doesn't define the date event, do it here as we
47 #if !wxUSE_DATEPICKCTRL
48 #define _WX_DEFINE_DATE_EVENTS_
51 #include "wx/calctrl.h"
55 // ----------------------------------------------------------------------------
57 // ----------------------------------------------------------------------------
59 class wxMonthComboBox
: public wxComboBox
62 wxMonthComboBox(wxCalendarCtrl
*cal
);
64 void OnMonthChange(wxCommandEvent
& event
) { m_cal
->OnMonthChange(event
); }
67 wxCalendarCtrl
*m_cal
;
70 DECLARE_NO_COPY_CLASS(wxMonthComboBox
)
73 class wxYearSpinCtrl
: public wxSpinCtrl
76 wxYearSpinCtrl(wxCalendarCtrl
*cal
);
78 void OnYearTextChange(wxCommandEvent
& event
)
80 m_cal
->SetUserChangedYear();
81 m_cal
->OnYearChange(event
);
83 void OnYearChange(wxSpinEvent
& event
) { m_cal
->OnYearChange(event
); }
86 wxCalendarCtrl
*m_cal
;
89 DECLARE_NO_COPY_CLASS(wxYearSpinCtrl
)
92 // ----------------------------------------------------------------------------
94 // ----------------------------------------------------------------------------
96 BEGIN_EVENT_TABLE(wxCalendarCtrl
, wxControl
)
97 EVT_PAINT(wxCalendarCtrl::OnPaint
)
99 EVT_CHAR(wxCalendarCtrl::OnChar
)
101 EVT_LEFT_DOWN(wxCalendarCtrl::OnClick
)
102 EVT_LEFT_DCLICK(wxCalendarCtrl::OnDClick
)
105 BEGIN_EVENT_TABLE(wxMonthComboBox
, wxComboBox
)
106 EVT_COMBOBOX(wxID_ANY
, wxMonthComboBox::OnMonthChange
)
109 BEGIN_EVENT_TABLE(wxYearSpinCtrl
, wxSpinCtrl
)
110 EVT_TEXT(wxID_ANY
, wxYearSpinCtrl::OnYearTextChange
)
111 EVT_SPINCTRL(wxID_ANY
, wxYearSpinCtrl::OnYearChange
)
114 #if wxUSE_EXTENDED_RTTI
115 WX_DEFINE_FLAGS( wxCalendarCtrlStyle
)
117 wxBEGIN_FLAGS( wxCalendarCtrlStyle
)
118 // new style border flags, we put them first to
119 // use them for streaming out
120 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
121 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
122 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
123 wxFLAGS_MEMBER(wxBORDER_RAISED
)
124 wxFLAGS_MEMBER(wxBORDER_STATIC
)
125 wxFLAGS_MEMBER(wxBORDER_NONE
)
127 // old style border flags
128 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
129 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
130 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
131 wxFLAGS_MEMBER(wxRAISED_BORDER
)
132 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
133 wxFLAGS_MEMBER(wxBORDER
)
135 // standard window styles
136 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
137 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
138 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
139 wxFLAGS_MEMBER(wxWANTS_CHARS
)
140 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
141 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
142 wxFLAGS_MEMBER(wxVSCROLL
)
143 wxFLAGS_MEMBER(wxHSCROLL
)
145 wxFLAGS_MEMBER(wxCAL_SUNDAY_FIRST
)
146 wxFLAGS_MEMBER(wxCAL_MONDAY_FIRST
)
147 wxFLAGS_MEMBER(wxCAL_SHOW_HOLIDAYS
)
148 wxFLAGS_MEMBER(wxCAL_NO_YEAR_CHANGE
)
149 wxFLAGS_MEMBER(wxCAL_NO_MONTH_CHANGE
)
150 wxFLAGS_MEMBER(wxCAL_SEQUENTIAL_MONTH_SELECTION
)
151 wxFLAGS_MEMBER(wxCAL_SHOW_SURROUNDING_WEEKS
)
153 wxEND_FLAGS( wxCalendarCtrlStyle
)
155 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCalendarCtrl
, wxControl
,"wx/calctrl.h")
157 wxBEGIN_PROPERTIES_TABLE(wxCalendarCtrl
)
158 wxEVENT_RANGE_PROPERTY( Updated
, wxEVT_CALENDAR_SEL_CHANGED
, wxEVT_CALENDAR_WEEKDAY_CLICKED
, wxCalendarEvent
)
159 wxHIDE_PROPERTY( Children
)
160 wxPROPERTY( Date
,wxDateTime
, SetDate
, GetDate
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
161 wxPROPERTY_FLAGS( WindowStyle
, wxCalendarCtrlStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
162 wxEND_PROPERTIES_TABLE()
164 wxBEGIN_HANDLERS_TABLE(wxCalendarCtrl
)
165 wxEND_HANDLERS_TABLE()
167 wxCONSTRUCTOR_6( wxCalendarCtrl
, wxWindow
* , Parent
, wxWindowID
, Id
, wxDateTime
, Date
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
169 IMPLEMENT_DYNAMIC_CLASS(wxCalendarCtrl
, wxControl
)
171 IMPLEMENT_DYNAMIC_CLASS(wxCalendarEvent
, wxDateEvent
)
173 // ----------------------------------------------------------------------------
175 // ----------------------------------------------------------------------------
177 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_SEL_CHANGED
)
178 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DAY_CHANGED
)
179 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_MONTH_CHANGED
)
180 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_YEAR_CHANGED
)
181 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DOUBLECLICKED
)
182 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_WEEKDAY_CLICKED
)
184 // ============================================================================
186 // ============================================================================
188 // ----------------------------------------------------------------------------
189 // wxMonthComboBox and wxYearSpinCtrl
190 // ----------------------------------------------------------------------------
192 wxMonthComboBox::wxMonthComboBox(wxCalendarCtrl
*cal
)
193 : wxComboBox(cal
->GetParent(), wxID_ANY
,
198 wxCB_READONLY
| wxCLIP_SIBLINGS
)
203 for ( m
= wxDateTime::Jan
; m
< wxDateTime::Inv_Month
; wxNextMonth(m
) )
205 Append(wxDateTime::GetMonthName(m
));
208 SetSelection(m_cal
->GetDate().GetMonth());
209 SetSize(wxDefaultCoord
,
213 wxSIZE_AUTO_WIDTH
|wxSIZE_AUTO_HEIGHT
);
216 wxYearSpinCtrl::wxYearSpinCtrl(wxCalendarCtrl
*cal
)
217 : wxSpinCtrl(cal
->GetParent(), wxID_ANY
,
218 cal
->GetDate().Format(_T("%Y")),
221 wxSP_ARROW_KEYS
| wxCLIP_SIBLINGS
,
222 -4300, 10000, cal
->GetDate().GetYear())
228 // ----------------------------------------------------------------------------
230 // ----------------------------------------------------------------------------
232 wxCalendarCtrl::wxCalendarCtrl(wxWindow
*parent
,
234 const wxDateTime
& date
,
238 const wxString
& name
)
242 (void)Create(parent
, id
, date
, pos
, size
, style
, name
);
245 void wxCalendarCtrl::Init()
250 m_staticMonth
= NULL
;
252 m_userChangedYear
= false;
257 wxDateTime::WeekDay wd
;
258 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
260 m_weekdays
[wd
] = wxDateTime::GetWeekDayName(wd
, wxDateTime::Name_Abbr
);
263 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
268 m_colHighlightFg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
269 m_colHighlightBg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
);
271 m_colHolidayFg
= *wxRED
;
272 // don't set m_colHolidayBg - by default, same as our bg colour
274 m_colHeaderFg
= *wxBLUE
;
275 m_colHeaderBg
= *wxLIGHT_GREY
;
278 bool wxCalendarCtrl::Create(wxWindow
*parent
,
280 const wxDateTime
& date
,
284 const wxString
& name
)
286 if ( !wxControl::Create(parent
, id
, pos
, size
,
287 style
| wxCLIP_CHILDREN
| wxWANTS_CHARS
,
288 wxDefaultValidator
, name
) )
293 // needed to get the arrow keys normally used for the dialog navigation
294 SetWindowStyle(style
| wxWANTS_CHARS
);
296 m_date
= date
.IsValid() ? date
: wxDateTime::Today();
298 m_lowdate
= wxDefaultDateTime
;
299 m_highdate
= wxDefaultDateTime
;
301 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
303 m_spinYear
= new wxYearSpinCtrl(this);
304 m_staticYear
= new wxStaticText(GetParent(), wxID_ANY
, m_date
.Format(_T("%Y")),
305 wxDefaultPosition
, wxDefaultSize
,
308 m_comboMonth
= new wxMonthComboBox(this);
309 m_staticMonth
= new wxStaticText(GetParent(), wxID_ANY
, m_date
.Format(_T("%B")),
310 wxDefaultPosition
, wxDefaultSize
,
314 ShowCurrentControls();
316 // we need to set the position as well because the main control position
317 // is not the same as the one specified in pos if we have the controls
322 // Since we don't paint the whole background make sure that the platform
323 // will use the right one.
324 SetBackgroundColour(GetBackgroundColour());
331 wxCalendarCtrl::~wxCalendarCtrl()
333 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
339 // ----------------------------------------------------------------------------
340 // forward wxWin functions to subcontrols
341 // ----------------------------------------------------------------------------
343 bool wxCalendarCtrl::Destroy()
346 m_staticYear
->Destroy();
348 m_spinYear
->Destroy();
350 m_comboMonth
->Destroy();
352 m_staticMonth
->Destroy();
357 m_staticMonth
= NULL
;
359 return wxControl::Destroy();
362 bool wxCalendarCtrl::Show(bool show
)
364 if ( !wxControl::Show(show
) )
369 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
371 if ( GetMonthControl() )
373 GetMonthControl()->Show(show
);
374 GetYearControl()->Show(show
);
381 bool wxCalendarCtrl::Enable(bool enable
)
383 if ( !wxControl::Enable(enable
) )
388 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
390 GetMonthControl()->Enable(enable
);
391 GetYearControl()->Enable(enable
);
397 // ----------------------------------------------------------------------------
398 // enable/disable month/year controls
399 // ----------------------------------------------------------------------------
401 void wxCalendarCtrl::ShowCurrentControls()
403 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
405 if ( AllowMonthChange() )
407 m_comboMonth
->Show();
408 m_staticMonth
->Hide();
410 if ( AllowYearChange() )
413 m_staticYear
->Hide();
421 m_comboMonth
->Hide();
422 m_staticMonth
->Show();
425 // year change not allowed here
427 m_staticYear
->Show();
431 wxControl
*wxCalendarCtrl::GetMonthControl() const
433 return AllowMonthChange() ? (wxControl
*)m_comboMonth
: (wxControl
*)m_staticMonth
;
436 wxControl
*wxCalendarCtrl::GetYearControl() const
438 return AllowYearChange() ? (wxControl
*)m_spinYear
: (wxControl
*)m_staticYear
;
441 void wxCalendarCtrl::EnableYearChange(bool enable
)
443 if ( enable
!= AllowYearChange() )
445 long style
= GetWindowStyle();
447 style
&= ~wxCAL_NO_YEAR_CHANGE
;
449 style
|= wxCAL_NO_YEAR_CHANGE
;
450 SetWindowStyle(style
);
452 ShowCurrentControls();
453 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
460 void wxCalendarCtrl::EnableMonthChange(bool enable
)
462 if ( enable
!= AllowMonthChange() )
464 long style
= GetWindowStyle();
466 style
&= ~wxCAL_NO_MONTH_CHANGE
;
468 style
|= wxCAL_NO_MONTH_CHANGE
;
469 SetWindowStyle(style
);
471 ShowCurrentControls();
472 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
479 // ----------------------------------------------------------------------------
481 // ----------------------------------------------------------------------------
483 bool wxCalendarCtrl::SetDate(const wxDateTime
& date
)
487 bool sameMonth
= m_date
.GetMonth() == date
.GetMonth(),
488 sameYear
= m_date
.GetYear() == date
.GetYear();
490 if ( IsDateInRange(date
) )
492 if ( sameMonth
&& sameYear
)
494 // just change the day
499 if ( AllowMonthChange() && (AllowYearChange() || sameYear
) )
504 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
506 // update the controls
507 m_comboMonth
->SetSelection(m_date
.GetMonth());
509 if ( AllowYearChange() )
511 if ( !m_userChangedYear
)
512 m_spinYear
->SetValue(m_date
.Format(_T("%Y")));
516 // as the month changed, holidays did too
519 // update the calendar
530 m_userChangedYear
= false;
535 void wxCalendarCtrl::ChangeDay(const wxDateTime
& date
)
537 if ( m_date
!= date
)
539 // we need to refresh the row containing the old date and the one
540 // containing the new one
541 wxDateTime dateOld
= m_date
;
544 RefreshDate(dateOld
);
546 // if the date is in the same row, it was already drawn correctly
547 if ( GetWeek(m_date
) != GetWeek(dateOld
) )
554 void wxCalendarCtrl::SetDateAndNotify(const wxDateTime
& date
)
556 wxDateTime::Tm tm1
= m_date
.GetTm(),
560 if ( tm1
.year
!= tm2
.year
)
561 type
= wxEVT_CALENDAR_YEAR_CHANGED
;
562 else if ( tm1
.mon
!= tm2
.mon
)
563 type
= wxEVT_CALENDAR_MONTH_CHANGED
;
564 else if ( tm1
.mday
!= tm2
.mday
)
565 type
= wxEVT_CALENDAR_DAY_CHANGED
;
571 GenerateEvents(type
, wxEVT_CALENDAR_SEL_CHANGED
);
575 // ----------------------------------------------------------------------------
577 // ----------------------------------------------------------------------------
579 bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
583 if ( !(date
.IsValid()) || ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) )
595 bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
599 if ( !(date
.IsValid()) || ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true ) )
611 bool wxCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
/* = wxDefaultDateTime */, const wxDateTime
& upperdate
/* = wxDefaultDateTime */)
616 ( !( lowerdate
.IsValid() ) || ( ( upperdate
.IsValid() ) ? ( lowerdate
<= upperdate
) : true ) ) &&
617 ( !( upperdate
.IsValid() ) || ( ( lowerdate
.IsValid() ) ? ( upperdate
>= lowerdate
) : true ) ) )
619 m_lowdate
= lowerdate
;
620 m_highdate
= upperdate
;
630 // ----------------------------------------------------------------------------
632 // ----------------------------------------------------------------------------
634 wxDateTime
wxCalendarCtrl::GetStartDate() const
636 wxDateTime::Tm tm
= m_date
.GetTm();
638 wxDateTime date
= wxDateTime(1, tm
.mon
, tm
.year
);
641 date
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
642 ? wxDateTime::Mon
: wxDateTime::Sun
);
644 if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
)
646 // We want to offset the calendar if we start on the first..
647 if ( date
.GetDay() == 1 )
649 date
-= wxDateSpan::Week();
656 bool wxCalendarCtrl::IsDateShown(const wxDateTime
& date
) const
658 if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
660 return date
.GetMonth() == m_date
.GetMonth();
668 bool wxCalendarCtrl::IsDateInRange(const wxDateTime
& date
) const
670 // Check if the given date is in the range specified
671 return ( ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true )
672 && ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) );
675 bool wxCalendarCtrl::ChangeYear(wxDateTime
* target
) const
679 if ( !(IsDateInRange(*target
)) )
681 if ( target
->GetYear() < m_date
.GetYear() )
683 if ( target
->GetYear() >= GetLowerDateLimit().GetYear() )
685 *target
= GetLowerDateLimit();
695 if ( target
->GetYear() <= GetUpperDateLimit().GetYear() )
697 *target
= GetUpperDateLimit();
714 bool wxCalendarCtrl::ChangeMonth(wxDateTime
* target
) const
718 if ( !(IsDateInRange(*target
)) )
722 if ( target
->GetMonth() < m_date
.GetMonth() )
724 *target
= GetLowerDateLimit();
728 *target
= GetUpperDateLimit();
735 size_t wxCalendarCtrl::GetWeek(const wxDateTime
& date
) const
737 size_t retval
= date
.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
738 ? wxDateTime::Monday_First
739 : wxDateTime::Sunday_First
);
741 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
743 // we need to offset an extra week if we "start" on the 1st of the month
744 wxDateTime::Tm tm
= date
.GetTm();
746 wxDateTime datetest
= wxDateTime(1, tm
.mon
, tm
.year
);
749 datetest
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
750 ? wxDateTime::Mon
: wxDateTime::Sun
);
752 if ( datetest
.GetDay() == 1 )
761 // ----------------------------------------------------------------------------
763 // ----------------------------------------------------------------------------
765 // this is a composite control and it must arrange its parts each time its
766 // size or position changes: the combobox and spinctrl are along the top of
767 // the available area and the calendar takes up therest of the space
769 // the static controls are supposed to be always smaller than combo/spin so we
770 // always use the latter for size calculations and position the static to take
773 // the constants used for the layout
774 #define VERT_MARGIN 5 // distance between combo and calendar
776 #define HORZ_MARGIN 5 // spin
778 #define HORZ_MARGIN 15 // spin
780 wxSize
wxCalendarCtrl::DoGetBestSize() const
782 // calc the size of the calendar
783 ((wxCalendarCtrl
*)this)->RecalcGeometry(); // const_cast
785 wxCoord width
= 7*m_widthCol
,
786 height
= 7*m_heightRow
+ m_rowOffset
+ VERT_MARGIN
;
788 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
790 // the combobox doesn't report its height correctly (it returns the
791 // height including the drop down list) so don't use it
792 height
+= m_spinYear
->GetBestSize().y
;
795 if ( !HasFlag(wxBORDER_NONE
) )
797 // the border would clip the last line otherwise
802 wxSize
best(width
, height
);
807 void wxCalendarCtrl::DoSetSize(int x
, int y
,
808 int width
, int height
,
811 wxControl::DoSetSize(x
, y
, width
, height
, sizeFlags
);
814 void wxCalendarCtrl::DoMoveWindow(int x
, int y
, int width
, int height
)
818 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
820 wxSize sizeCombo
= m_comboMonth
->GetSize();
821 wxSize sizeStatic
= m_staticMonth
->GetSize();
822 wxSize sizeSpin
= m_spinYear
->GetSize();
823 int dy
= (sizeCombo
.y
- sizeStatic
.y
) / 2;
825 In the calender the size of the combobox for the year
826 is just defined by a margin from the month combobox to
827 the left border. While in wxUniv the year control can't
828 show all 4 digits, in wxMsw it show almost twice as
829 much. Instead the year should use it's best size and be
830 left aligned to the calendar. Just in case the month in
831 any language is longer than it has space in the
832 calendar it is shortend.This way the year always can
835 This patch relies on the fact that a combobox has a
836 good best size implementation. This is not the case
837 with wxMSW but I don't know why.
842 #ifdef __WXUNIVERSAL__
843 if (sizeCombo
.x
+ HORZ_MARGIN
- sizeSpin
.x
> width
)
845 m_comboMonth
->SetSize(x
, y
, width
- HORZ_MARGIN
- sizeSpin
.x
, sizeCombo
.y
);
849 m_comboMonth
->Move(x
, y
);
851 m_staticMonth
->Move(x
, y
+ dy
);
852 m_spinYear
->Move(x
+ width
- sizeSpin
.x
, y
);
853 m_staticYear
->Move(x
+ width
- sizeSpin
.x
, y
+ dy
);
855 m_comboMonth
->Move(x
, y
);
856 m_staticMonth
->SetSize(x
, y
+ dy
, sizeCombo
.x
, sizeStatic
.y
);
858 int xDiff
= sizeCombo
.x
+ HORZ_MARGIN
;
860 m_spinYear
->SetSize(x
+ xDiff
, y
, width
- xDiff
, sizeCombo
.y
);
861 m_staticYear
->SetSize(x
+ xDiff
, y
+ dy
, width
- xDiff
, sizeStatic
.y
);
863 yDiff
= wxMax(sizeSpin
.y
, sizeCombo
.y
) + VERT_MARGIN
;
865 else // no controls on the top
870 wxControl::DoMoveWindow(x
, y
+ yDiff
, width
, height
- yDiff
);
873 void wxCalendarCtrl::DoGetPosition(int *x
, int *y
) const
875 wxControl::DoGetPosition(x
, y
);
877 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
879 // our real top corner is not in this position
882 *y
-= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
887 void wxCalendarCtrl::DoGetSize(int *width
, int *height
) const
889 wxControl::DoGetSize(width
, height
);
891 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
893 // our real height is bigger
894 if ( height
&& GetMonthControl())
896 *height
+= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
901 void wxCalendarCtrl::RecalcGeometry()
905 dc
.SetFont(GetFont());
907 // determine the column width (we assume that the weekday names are always
908 // wider (in any language) than the numbers)
910 wxDateTime::WeekDay wd
;
911 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
914 dc
.GetTextExtent(m_weekdays
[wd
], &width
, &m_heightRow
);
915 if ( width
> m_widthCol
)
921 // leave some margins
925 m_rowOffset
= (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) ? m_heightRow
: 0; // conditional in relation to style
928 // ----------------------------------------------------------------------------
930 // ----------------------------------------------------------------------------
932 void wxCalendarCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
))
936 dc
.SetFont(GetFont());
941 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
942 m_date
.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
948 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
950 // draw the sequential month-selector
952 dc
.SetBackgroundMode(wxTRANSPARENT
);
953 dc
.SetTextForeground(*wxBLACK
);
954 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
955 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
956 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
958 // Get extent of month-name + year
959 wxCoord monthw
, monthh
;
960 wxString headertext
= m_date
.Format(wxT("%B %Y"));
961 dc
.GetTextExtent(headertext
, &monthw
, &monthh
);
963 // draw month-name centered above weekdays
964 wxCoord monthx
= ((m_widthCol
* 7) - monthw
) / 2;
965 wxCoord monthy
= ((m_heightRow
- monthh
) / 2) + y
;
966 dc
.DrawText(headertext
, monthx
, monthy
);
968 // calculate the "month-arrows"
969 wxPoint leftarrow
[3];
970 wxPoint rightarrow
[3];
972 int arrowheight
= monthh
/ 2;
974 leftarrow
[0] = wxPoint(0, arrowheight
/ 2);
975 leftarrow
[1] = wxPoint(arrowheight
/ 2, 0);
976 leftarrow
[2] = wxPoint(arrowheight
/ 2, arrowheight
- 1);
978 rightarrow
[0] = wxPoint(0,0);
979 rightarrow
[1] = wxPoint(arrowheight
/ 2, arrowheight
/ 2);
980 rightarrow
[2] = wxPoint(0, arrowheight
- 1);
982 // draw the "month-arrows"
984 wxCoord arrowy
= (m_heightRow
- arrowheight
) / 2;
985 wxCoord larrowx
= (m_widthCol
- (arrowheight
/ 2)) / 2;
986 wxCoord rarrowx
= ((m_widthCol
- (arrowheight
/ 2)) / 2) + m_widthCol
*6;
987 m_leftArrowRect
= m_rightArrowRect
= wxRect(0,0,0,0);
989 if ( AllowMonthChange() )
991 wxDateTime ldpm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) - wxDateSpan::Day(); // last day prev month
992 // Check if range permits change
993 if ( IsDateInRange(ldpm
) && ( ( ldpm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
995 m_leftArrowRect
= wxRect(larrowx
- 3, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
996 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
997 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
998 dc
.DrawPolygon(3, leftarrow
, larrowx
, arrowy
, wxWINDING_RULE
);
999 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1000 dc
.DrawRectangle(m_leftArrowRect
);
1002 wxDateTime fdnm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) + wxDateSpan::Month(); // first day next month
1003 if ( IsDateInRange(fdnm
) && ( ( fdnm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
1005 m_rightArrowRect
= wxRect(rarrowx
- 4, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1006 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1007 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1008 dc
.DrawPolygon(3, rightarrow
, rarrowx
, arrowy
, wxWINDING_RULE
);
1009 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1010 dc
.DrawRectangle(m_rightArrowRect
);
1017 // first draw the week days
1018 if ( IsExposed(0, y
, 7*m_widthCol
, m_heightRow
) )
1021 wxLogDebug("painting the header");
1024 dc
.SetBackgroundMode(wxTRANSPARENT
);
1025 dc
.SetTextForeground(m_colHeaderFg
);
1026 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
1027 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
1028 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
1030 bool startOnMonday
= (GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1031 for ( size_t wd
= 0; wd
< 7; wd
++ )
1034 if ( startOnMonday
)
1035 n
= wd
== 6 ? 0 : wd
+ 1;
1039 dc
.GetTextExtent(m_weekdays
[n
], &dayw
, &dayh
);
1040 dc
.DrawText(m_weekdays
[n
], (wd
*m_widthCol
) + ((m_widthCol
- dayw
) / 2), y
); // center the day-name
1044 // then the calendar itself
1045 dc
.SetTextForeground(*wxBLACK
);
1046 //dc.SetFont(*wxNORMAL_FONT);
1049 wxDateTime date
= GetStartDate();
1052 wxLogDebug("starting calendar from %s\n",
1053 date
.Format("%a %d-%m-%Y %H:%M:%S").c_str());
1056 dc
.SetBackgroundMode(wxSOLID
);
1057 for ( size_t nWeek
= 1; nWeek
<= 6; nWeek
++, y
+= m_heightRow
)
1059 // if the update region doesn't intersect this row, don't paint it
1060 if ( !IsExposed(0, y
, 7*m_widthCol
, m_heightRow
- 1) )
1062 date
+= wxDateSpan::Week();
1068 wxLogDebug("painting week %d at y = %d\n", nWeek
, y
);
1071 for ( size_t wd
= 0; wd
< 7; wd
++ )
1073 if ( IsDateShown(date
) )
1075 // don't use wxDate::Format() which prepends 0s
1076 unsigned int day
= date
.GetDay();
1077 wxString dayStr
= wxString::Format(_T("%u"), day
);
1079 dc
.GetTextExtent(dayStr
, &width
, (wxCoord
*)NULL
);
1081 bool changedColours
= false,
1082 changedFont
= false;
1085 wxCalendarDateAttr
*attr
= NULL
;
1087 if ( date
.GetMonth() != m_date
.GetMonth() || !IsDateInRange(date
) )
1089 // surrounding week or out-of-range
1091 dc
.SetTextForeground(*wxLIGHT_GREY
);
1092 changedColours
= true;
1096 isSel
= date
.IsSameDate(m_date
);
1097 attr
= m_attrs
[day
- 1];
1101 dc
.SetTextForeground(m_colHighlightFg
);
1102 dc
.SetTextBackground(m_colHighlightBg
);
1104 changedColours
= true;
1108 wxColour colFg
, colBg
;
1110 if ( attr
->IsHoliday() )
1112 colFg
= m_colHolidayFg
;
1113 colBg
= m_colHolidayBg
;
1117 colFg
= attr
->GetTextColour();
1118 colBg
= attr
->GetBackgroundColour();
1123 dc
.SetTextForeground(colFg
);
1124 changedColours
= true;
1129 dc
.SetTextBackground(colBg
);
1130 changedColours
= true;
1133 if ( attr
->HasFont() )
1135 dc
.SetFont(attr
->GetFont());
1141 wxCoord x
= wd
*m_widthCol
+ (m_widthCol
- width
) / 2;
1142 dc
.DrawText(dayStr
, x
, y
+ 1);
1144 if ( !isSel
&& attr
&& attr
->HasBorder() )
1147 if ( attr
->HasBorderColour() )
1149 colBorder
= attr
->GetBorderColour();
1153 colBorder
= GetForegroundColour();
1156 wxPen
pen(colBorder
, 1, wxSOLID
);
1158 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1160 switch ( attr
->GetBorder() )
1162 case wxCAL_BORDER_SQUARE
:
1163 dc
.DrawRectangle(x
- 2, y
,
1164 width
+ 4, m_heightRow
);
1167 case wxCAL_BORDER_ROUND
:
1168 dc
.DrawEllipse(x
- 2, y
,
1169 width
+ 4, m_heightRow
);
1173 wxFAIL_MSG(_T("unknown border type"));
1177 if ( changedColours
)
1179 dc
.SetTextForeground(GetForegroundColour());
1180 dc
.SetTextBackground(GetBackgroundColour());
1185 dc
.SetFont(GetFont());
1188 //else: just don't draw it
1190 date
+= wxDateSpan::Day();
1194 // Greying out out-of-range background
1195 bool showSurrounding
= (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) != 0;
1197 date
= ( showSurrounding
) ? GetStartDate() : wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear());
1198 if ( !IsDateInRange(date
) )
1200 wxDateTime firstOOR
= GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1202 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1203 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1205 HighlightRange(&dc
, date
, firstOOR
, wxTRANSPARENT_PEN
, &oorbrush
);
1208 date
= ( showSurrounding
) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear());
1209 if ( !IsDateInRange(date
) )
1211 wxDateTime firstOOR
= GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1213 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1214 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1216 HighlightRange(&dc
, firstOOR
, date
, wxTRANSPARENT_PEN
, &oorbrush
);
1220 wxLogDebug("+++ finished painting");
1224 void wxCalendarCtrl::RefreshDate(const wxDateTime
& date
)
1230 // always refresh the whole row at once because our OnPaint() will draw
1231 // the whole row anyhow - and this allows the small optimisation in
1232 // OnClick() below to work
1235 rect
.y
= (m_heightRow
* GetWeek(date
)) + m_rowOffset
;
1237 rect
.width
= 7*m_widthCol
;
1238 rect
.height
= m_heightRow
;
1241 // VZ: for some reason, the selected date seems to occupy more space under
1242 // MSW - this is probably some bug in the font size calculations, but I
1243 // don't know where exactly. This fix is ugly and leads to more
1244 // refreshes than really needed, but without it the selected days
1245 // leaves even more ugly underscores on screen.
1250 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
1253 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
1256 Refresh(true, &rect
);
1259 void wxCalendarCtrl::HighlightRange(wxPaintDC
* pDC
, const wxDateTime
& fromdate
, const wxDateTime
& todate
, wxPen
* pPen
, wxBrush
* pBrush
)
1261 // Highlights the given range using pen and brush
1262 // Does nothing if todate < fromdate
1266 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate
.Format("%d %m %Y"), todate
.Format("%d %m %Y"));
1269 if ( todate
>= fromdate
)
1276 // implicit: both dates must be currently shown - checked by GetDateCoord
1277 if ( GetDateCoord(fromdate
, &fd
, &fw
) && GetDateCoord(todate
, &td
, &tw
) )
1280 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd
, fw
, td
, tw
);
1282 if ( ( (tw
- fw
) == 1 ) && ( td
< fd
) )
1284 // special case: interval 7 days or less not in same week
1285 // split in two seperate intervals
1286 wxDateTime tfd
= fromdate
+ wxDateSpan::Days(7-fd
);
1287 wxDateTime ftd
= tfd
+ wxDateSpan::Day();
1289 wxLogDebug("Highlight: Seperate segments");
1292 HighlightRange(pDC
, fromdate
, tfd
, pPen
, pBrush
);
1293 HighlightRange(pDC
, ftd
, todate
, pPen
, pBrush
);
1298 wxPoint corners
[8]; // potentially 8 corners in polygon
1302 // simple case: same week
1304 corners
[0] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
);
1305 corners
[1] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1 ) * m_heightRow
) + m_rowOffset
);
1306 corners
[2] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
);
1307 corners
[3] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
);
1312 // "complex" polygon
1313 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1317 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1318 corners
[cidx
] = wxPoint(0, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1321 corners
[cidx
] = wxPoint(0, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1322 corners
[cidx
] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1326 corners
[cidx
] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1327 corners
[cidx
] = wxPoint(7 * m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1330 corners
[cidx
] = wxPoint(7 * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1336 pDC
->SetBrush(*pBrush
);
1338 pDC
->DrawPolygon(numpoints
, corners
);
1344 wxLogDebug("--- HighlightRange ---");
1348 bool wxCalendarCtrl::GetDateCoord(const wxDateTime
& date
, int *day
, int *week
) const
1353 wxLogDebug("+++ GetDateCoord: (%s) +++", date
.Format("%d %m %Y"));
1356 if ( IsDateShown(date
) )
1358 bool startOnMonday
= ( GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1361 *day
= date
.GetWeekDay();
1363 if ( *day
== 0 ) // sunday
1365 *day
= ( startOnMonday
) ? 7 : 1;
1369 *day
+= ( startOnMonday
) ? 0 : 1;
1372 int targetmonth
= date
.GetMonth() + (12 * date
.GetYear());
1373 int thismonth
= m_date
.GetMonth() + (12 * m_date
.GetYear());
1376 if ( targetmonth
== thismonth
)
1378 *week
= GetWeek(date
);
1382 if ( targetmonth
< thismonth
)
1384 *week
= 1; // trivial
1386 else // targetmonth > thismonth
1392 // get the datecoord of the last day in the month currently shown
1394 wxLogDebug(" +++ LDOM +++");
1396 GetDateCoord(ldcm
.SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear()), &lastday
, &lastweek
);
1398 wxLogDebug(" --- LDOM ---");
1401 wxTimeSpan span
= date
- ldcm
;
1403 int daysfromlast
= span
.GetDays();
1405 wxLogDebug("daysfromlast: %i", daysfromlast
);
1407 if ( daysfromlast
+ lastday
> 7 ) // past week boundary
1409 int wholeweeks
= (daysfromlast
/ 7);
1410 *week
= wholeweeks
+ lastweek
;
1411 if ( (daysfromlast
- (7 * wholeweeks
) + lastday
) > 7 )
1431 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date
.Format("%d %m %Y"), *day
, *week
);
1437 // ----------------------------------------------------------------------------
1439 // ----------------------------------------------------------------------------
1441 void wxCalendarCtrl::OnDClick(wxMouseEvent
& event
)
1443 if ( HitTest(event
.GetPosition()) != wxCAL_HITTEST_DAY
)
1449 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1453 void wxCalendarCtrl::OnClick(wxMouseEvent
& event
)
1456 wxDateTime::WeekDay wday
;
1457 switch ( HitTest(event
.GetPosition(), &date
, &wday
) )
1459 case wxCAL_HITTEST_DAY
:
1460 if ( IsDateInRange(date
) )
1464 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED
,
1465 wxEVT_CALENDAR_SEL_CHANGED
);
1469 case wxCAL_HITTEST_HEADER
:
1471 wxCalendarEvent
event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED
);
1472 event
.m_wday
= wday
;
1473 (void)GetEventHandler()->ProcessEvent(event
);
1477 case wxCAL_HITTEST_DECMONTH
:
1478 case wxCAL_HITTEST_INCMONTH
:
1479 case wxCAL_HITTEST_SURROUNDING_WEEK
:
1480 SetDateAndNotify(date
); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1484 wxFAIL_MSG(_T("unknown hittest code"));
1487 case wxCAL_HITTEST_NOWHERE
:
1493 wxCalendarHitTestResult
wxCalendarCtrl::HitTest(const wxPoint
& pos
,
1495 wxDateTime::WeekDay
*wd
)
1501 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1502 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
1506 // we need to find out if the hit is on left arrow, on month or on right arrow
1508 if ( wxRegion(m_leftArrowRect
).Contains(pos
) == wxInRegion
)
1512 if ( IsDateInRange(m_date
- wxDateSpan::Month()) )
1514 *date
= m_date
- wxDateSpan::Month();
1518 *date
= GetLowerDateLimit();
1522 return wxCAL_HITTEST_DECMONTH
;
1525 if ( wxRegion(m_rightArrowRect
).Contains(pos
) == wxInRegion
)
1529 if ( IsDateInRange(m_date
+ wxDateSpan::Month()) )
1531 *date
= m_date
+ wxDateSpan::Month();
1535 *date
= GetUpperDateLimit();
1539 return wxCAL_HITTEST_INCMONTH
;
1544 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1546 int wday
= pos
.x
/ m_widthCol
;
1547 // if ( y < m_heightRow )
1548 if ( y
< (m_heightRow
+ m_rowOffset
) )
1550 if ( y
> m_rowOffset
)
1554 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST
)
1556 wday
= wday
== 6 ? 0 : wday
+ 1;
1559 *wd
= (wxDateTime::WeekDay
)wday
;
1562 return wxCAL_HITTEST_HEADER
;
1566 return wxCAL_HITTEST_NOWHERE
;
1570 // int week = (y - m_heightRow) / m_heightRow;
1571 int week
= (y
- (m_heightRow
+ m_rowOffset
)) / m_heightRow
;
1572 if ( week
>= 6 || wday
>= 7 )
1574 return wxCAL_HITTEST_NOWHERE
;
1577 wxDateTime dt
= GetStartDate() + wxDateSpan::Days(7*week
+ wday
);
1579 if ( IsDateShown(dt
) )
1584 if ( dt
.GetMonth() == m_date
.GetMonth() )
1587 return wxCAL_HITTEST_DAY
;
1591 return wxCAL_HITTEST_SURROUNDING_WEEK
;
1596 return wxCAL_HITTEST_NOWHERE
;
1600 // ----------------------------------------------------------------------------
1601 // subcontrols events handling
1602 // ----------------------------------------------------------------------------
1604 void wxCalendarCtrl::OnMonthChange(wxCommandEvent
& event
)
1606 wxDateTime::Tm tm
= m_date
.GetTm();
1608 wxDateTime::Month mon
= (wxDateTime::Month
)event
.GetInt();
1609 if ( tm
.mday
> wxDateTime::GetNumberOfDays(mon
, tm
.year
) )
1611 tm
.mday
= wxDateTime::GetNumberOfDays(mon
, tm
.year
);
1614 wxDateTime target
= wxDateTime(tm
.mday
, mon
, tm
.year
);
1616 ChangeMonth(&target
);
1617 SetDateAndNotify(target
);
1620 void wxCalendarCtrl::OnYearChange(wxCommandEvent
& event
)
1622 int year
= (int)event
.GetInt();
1623 if ( year
== INT_MIN
)
1625 // invalid year in the spin control, ignore it
1629 wxDateTime::Tm tm
= m_date
.GetTm();
1631 if ( tm
.mday
> wxDateTime::GetNumberOfDays(tm
.mon
, year
) )
1633 tm
.mday
= wxDateTime::GetNumberOfDays(tm
.mon
, year
);
1636 wxDateTime target
= wxDateTime(tm
.mday
, tm
.mon
, year
);
1638 if ( ChangeYear(&target
) )
1640 SetDateAndNotify(target
);
1644 // In this case we don't want to change the date. That would put us
1645 // inside the same year but a strange number of months forward/back..
1646 m_spinYear
->SetValue(target
.GetYear());
1650 // ----------------------------------------------------------------------------
1651 // keyboard interface
1652 // ----------------------------------------------------------------------------
1654 void wxCalendarCtrl::OnChar(wxKeyEvent
& event
)
1657 switch ( event
.GetKeyCode() )
1661 target
= m_date
+ wxDateSpan::Year();
1662 if ( ChangeYear(&target
) )
1664 SetDateAndNotify(target
);
1670 target
= m_date
- wxDateSpan::Year();
1671 if ( ChangeYear(&target
) )
1673 SetDateAndNotify(target
);
1678 target
= m_date
- wxDateSpan::Month();
1679 ChangeMonth(&target
);
1680 SetDateAndNotify(target
); // always
1684 target
= m_date
+ wxDateSpan::Month();
1685 ChangeMonth(&target
);
1686 SetDateAndNotify(target
); // always
1690 if ( event
.ControlDown() )
1692 target
= wxDateTime(m_date
).SetToNextWeekDay(
1693 GetWindowStyle() & wxCAL_MONDAY_FIRST
1694 ? wxDateTime::Sun
: wxDateTime::Sat
);
1695 if ( !IsDateInRange(target
) )
1697 target
= GetUpperDateLimit();
1699 SetDateAndNotify(target
);
1702 SetDateAndNotify(m_date
+ wxDateSpan::Day());
1706 if ( event
.ControlDown() )
1708 target
= wxDateTime(m_date
).SetToPrevWeekDay(
1709 GetWindowStyle() & wxCAL_MONDAY_FIRST
1710 ? wxDateTime::Mon
: wxDateTime::Sun
);
1711 if ( !IsDateInRange(target
) )
1713 target
= GetLowerDateLimit();
1715 SetDateAndNotify(target
);
1718 SetDateAndNotify(m_date
- wxDateSpan::Day());
1722 SetDateAndNotify(m_date
- wxDateSpan::Week());
1726 SetDateAndNotify(m_date
+ wxDateSpan::Week());
1730 if ( event
.ControlDown() )
1731 SetDateAndNotify(wxDateTime::Today());
1733 SetDateAndNotify(wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear()));
1737 SetDateAndNotify(wxDateTime(m_date
).SetToLastMonthDay());
1741 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1749 // ----------------------------------------------------------------------------
1750 // holidays handling
1751 // ----------------------------------------------------------------------------
1753 void wxCalendarCtrl::EnableHolidayDisplay(bool display
)
1755 long style
= GetWindowStyle();
1757 style
|= wxCAL_SHOW_HOLIDAYS
;
1759 style
&= ~wxCAL_SHOW_HOLIDAYS
;
1761 SetWindowStyle(style
);
1766 ResetHolidayAttrs();
1771 void wxCalendarCtrl::SetHolidayAttrs()
1773 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS
)
1775 ResetHolidayAttrs();
1777 wxDateTime::Tm tm
= m_date
.GetTm();
1778 wxDateTime
dtStart(1, tm
.mon
, tm
.year
),
1779 dtEnd
= dtStart
.GetLastMonthDay();
1781 wxDateTimeArray hol
;
1782 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart
, dtEnd
, hol
);
1784 size_t count
= hol
.GetCount();
1785 for ( size_t n
= 0; n
< count
; n
++ )
1787 SetHoliday(hol
[n
].GetDay());
1792 void wxCalendarCtrl::SetHoliday(size_t day
)
1794 wxCHECK_RET( day
> 0 && day
< 32, _T("invalid day in SetHoliday") );
1796 wxCalendarDateAttr
*attr
= GetAttr(day
);
1799 attr
= new wxCalendarDateAttr
;
1802 attr
->SetHoliday(true);
1804 // can't use SetAttr() because it would delete this pointer
1805 m_attrs
[day
- 1] = attr
;
1808 void wxCalendarCtrl::ResetHolidayAttrs()
1810 for ( size_t day
= 0; day
< 31; day
++ )
1814 m_attrs
[day
]->SetHoliday(false);
1822 wxCalendarCtrl::GetClassDefaultAttributes(wxWindowVariant variant
)
1824 // Use the same color scheme as wxListBox
1825 return wxListBox::GetClassDefaultAttributes(variant
);
1828 #endif // wxUSE_CALENDARCTRL