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
= wxRect(0, 0, 0, 0);
988 m_rightArrowRect
= wxRect(0, 0, 0, 0);
990 if ( AllowMonthChange() )
992 wxDateTime ldpm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) - wxDateSpan::Day(); // last day prev month
993 // Check if range permits change
994 if ( IsDateInRange(ldpm
) && ( ( ldpm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
996 m_leftArrowRect
= wxRect(larrowx
- 3, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
997 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
998 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
999 dc
.DrawPolygon(3, leftarrow
, larrowx
, arrowy
, wxWINDING_RULE
);
1000 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1001 dc
.DrawRectangle(m_leftArrowRect
);
1003 wxDateTime fdnm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) + wxDateSpan::Month(); // first day next month
1004 if ( IsDateInRange(fdnm
) && ( ( fdnm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
1006 m_rightArrowRect
= wxRect(rarrowx
- 4, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1007 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1008 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1009 dc
.DrawPolygon(3, rightarrow
, rarrowx
, arrowy
, wxWINDING_RULE
);
1010 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1011 dc
.DrawRectangle(m_rightArrowRect
);
1018 // first draw the week days
1019 if ( IsExposed(0, y
, 7*m_widthCol
, m_heightRow
) )
1022 wxLogDebug("painting the header");
1025 dc
.SetBackgroundMode(wxTRANSPARENT
);
1026 dc
.SetTextForeground(m_colHeaderFg
);
1027 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
1028 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
1029 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
1031 bool startOnMonday
= (GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1032 for ( size_t wd
= 0; wd
< 7; wd
++ )
1035 if ( startOnMonday
)
1036 n
= wd
== 6 ? 0 : wd
+ 1;
1040 dc
.GetTextExtent(m_weekdays
[n
], &dayw
, &dayh
);
1041 dc
.DrawText(m_weekdays
[n
], (wd
*m_widthCol
) + ((m_widthCol
- dayw
) / 2), y
); // center the day-name
1045 // then the calendar itself
1046 dc
.SetTextForeground(*wxBLACK
);
1047 //dc.SetFont(*wxNORMAL_FONT);
1050 wxDateTime date
= GetStartDate();
1053 wxLogDebug("starting calendar from %s\n",
1054 date
.Format("%a %d-%m-%Y %H:%M:%S").c_str());
1057 dc
.SetBackgroundMode(wxSOLID
);
1058 for ( size_t nWeek
= 1; nWeek
<= 6; nWeek
++, y
+= m_heightRow
)
1060 // if the update region doesn't intersect this row, don't paint it
1061 if ( !IsExposed(0, y
, 7*m_widthCol
, m_heightRow
- 1) )
1063 date
+= wxDateSpan::Week();
1069 wxLogDebug("painting week %d at y = %d\n", nWeek
, y
);
1072 for ( size_t wd
= 0; wd
< 7; wd
++ )
1074 if ( IsDateShown(date
) )
1076 // don't use wxDate::Format() which prepends 0s
1077 unsigned int day
= date
.GetDay();
1078 wxString dayStr
= wxString::Format(_T("%u"), day
);
1080 dc
.GetTextExtent(dayStr
, &width
, (wxCoord
*)NULL
);
1082 bool changedColours
= false,
1083 changedFont
= false;
1086 wxCalendarDateAttr
*attr
= NULL
;
1088 if ( date
.GetMonth() != m_date
.GetMonth() || !IsDateInRange(date
) )
1090 // surrounding week or out-of-range
1092 dc
.SetTextForeground(*wxLIGHT_GREY
);
1093 changedColours
= true;
1097 isSel
= date
.IsSameDate(m_date
);
1098 attr
= m_attrs
[day
- 1];
1102 dc
.SetTextForeground(m_colHighlightFg
);
1103 dc
.SetTextBackground(m_colHighlightBg
);
1105 changedColours
= true;
1109 wxColour colFg
, colBg
;
1111 if ( attr
->IsHoliday() )
1113 colFg
= m_colHolidayFg
;
1114 colBg
= m_colHolidayBg
;
1118 colFg
= attr
->GetTextColour();
1119 colBg
= attr
->GetBackgroundColour();
1124 dc
.SetTextForeground(colFg
);
1125 changedColours
= true;
1130 dc
.SetTextBackground(colBg
);
1131 changedColours
= true;
1134 if ( attr
->HasFont() )
1136 dc
.SetFont(attr
->GetFont());
1142 wxCoord x
= wd
*m_widthCol
+ (m_widthCol
- width
) / 2;
1143 dc
.DrawText(dayStr
, x
, y
+ 1);
1145 if ( !isSel
&& attr
&& attr
->HasBorder() )
1148 if ( attr
->HasBorderColour() )
1150 colBorder
= attr
->GetBorderColour();
1154 colBorder
= GetForegroundColour();
1157 wxPen
pen(colBorder
, 1, wxSOLID
);
1159 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1161 switch ( attr
->GetBorder() )
1163 case wxCAL_BORDER_SQUARE
:
1164 dc
.DrawRectangle(x
- 2, y
,
1165 width
+ 4, m_heightRow
);
1168 case wxCAL_BORDER_ROUND
:
1169 dc
.DrawEllipse(x
- 2, y
,
1170 width
+ 4, m_heightRow
);
1174 wxFAIL_MSG(_T("unknown border type"));
1178 if ( changedColours
)
1180 dc
.SetTextForeground(GetForegroundColour());
1181 dc
.SetTextBackground(GetBackgroundColour());
1186 dc
.SetFont(GetFont());
1189 //else: just don't draw it
1191 date
+= wxDateSpan::Day();
1195 // Greying out out-of-range background
1196 bool showSurrounding
= (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) != 0;
1198 date
= ( showSurrounding
) ? GetStartDate() : wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear());
1199 if ( !IsDateInRange(date
) )
1201 wxDateTime firstOOR
= GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1203 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1204 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1206 HighlightRange(&dc
, date
, firstOOR
, wxTRANSPARENT_PEN
, &oorbrush
);
1209 date
= ( showSurrounding
) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear());
1210 if ( !IsDateInRange(date
) )
1212 wxDateTime firstOOR
= GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1214 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1215 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1217 HighlightRange(&dc
, firstOOR
, date
, wxTRANSPARENT_PEN
, &oorbrush
);
1221 wxLogDebug("+++ finished painting");
1225 void wxCalendarCtrl::RefreshDate(const wxDateTime
& date
)
1231 // always refresh the whole row at once because our OnPaint() will draw
1232 // the whole row anyhow - and this allows the small optimisation in
1233 // OnClick() below to work
1236 rect
.y
= (m_heightRow
* GetWeek(date
)) + m_rowOffset
;
1238 rect
.width
= 7*m_widthCol
;
1239 rect
.height
= m_heightRow
;
1242 // VZ: for some reason, the selected date seems to occupy more space under
1243 // MSW - this is probably some bug in the font size calculations, but I
1244 // don't know where exactly. This fix is ugly and leads to more
1245 // refreshes than really needed, but without it the selected days
1246 // leaves even more ugly underscores on screen.
1251 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
1254 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
1257 Refresh(true, &rect
);
1260 void wxCalendarCtrl::HighlightRange(wxPaintDC
* pDC
, const wxDateTime
& fromdate
, const wxDateTime
& todate
, wxPen
* pPen
, wxBrush
* pBrush
)
1262 // Highlights the given range using pen and brush
1263 // Does nothing if todate < fromdate
1267 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate
.Format("%d %m %Y"), todate
.Format("%d %m %Y"));
1270 if ( todate
>= fromdate
)
1277 // implicit: both dates must be currently shown - checked by GetDateCoord
1278 if ( GetDateCoord(fromdate
, &fd
, &fw
) && GetDateCoord(todate
, &td
, &tw
) )
1281 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd
, fw
, td
, tw
);
1283 if ( ( (tw
- fw
) == 1 ) && ( td
< fd
) )
1285 // special case: interval 7 days or less not in same week
1286 // split in two seperate intervals
1287 wxDateTime tfd
= fromdate
+ wxDateSpan::Days(7-fd
);
1288 wxDateTime ftd
= tfd
+ wxDateSpan::Day();
1290 wxLogDebug("Highlight: Seperate segments");
1293 HighlightRange(pDC
, fromdate
, tfd
, pPen
, pBrush
);
1294 HighlightRange(pDC
, ftd
, todate
, pPen
, pBrush
);
1299 wxPoint corners
[8]; // potentially 8 corners in polygon
1303 // simple case: same week
1305 corners
[0] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
);
1306 corners
[1] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1 ) * m_heightRow
) + m_rowOffset
);
1307 corners
[2] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
);
1308 corners
[3] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
);
1313 // "complex" polygon
1314 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1318 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1319 corners
[cidx
] = wxPoint(0, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1322 corners
[cidx
] = wxPoint(0, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1323 corners
[cidx
] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1327 corners
[cidx
] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1328 corners
[cidx
] = wxPoint(7 * m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1331 corners
[cidx
] = wxPoint(7 * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1337 pDC
->SetBrush(*pBrush
);
1339 pDC
->DrawPolygon(numpoints
, corners
);
1345 wxLogDebug("--- HighlightRange ---");
1349 bool wxCalendarCtrl::GetDateCoord(const wxDateTime
& date
, int *day
, int *week
) const
1354 wxLogDebug("+++ GetDateCoord: (%s) +++", date
.Format("%d %m %Y"));
1357 if ( IsDateShown(date
) )
1359 bool startOnMonday
= ( GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1362 *day
= date
.GetWeekDay();
1364 if ( *day
== 0 ) // sunday
1366 *day
= ( startOnMonday
) ? 7 : 1;
1370 *day
+= ( startOnMonday
) ? 0 : 1;
1373 int targetmonth
= date
.GetMonth() + (12 * date
.GetYear());
1374 int thismonth
= m_date
.GetMonth() + (12 * m_date
.GetYear());
1377 if ( targetmonth
== thismonth
)
1379 *week
= GetWeek(date
);
1383 if ( targetmonth
< thismonth
)
1385 *week
= 1; // trivial
1387 else // targetmonth > thismonth
1393 // get the datecoord of the last day in the month currently shown
1395 wxLogDebug(" +++ LDOM +++");
1397 GetDateCoord(ldcm
.SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear()), &lastday
, &lastweek
);
1399 wxLogDebug(" --- LDOM ---");
1402 wxTimeSpan span
= date
- ldcm
;
1404 int daysfromlast
= span
.GetDays();
1406 wxLogDebug("daysfromlast: %i", daysfromlast
);
1408 if ( daysfromlast
+ lastday
> 7 ) // past week boundary
1410 int wholeweeks
= (daysfromlast
/ 7);
1411 *week
= wholeweeks
+ lastweek
;
1412 if ( (daysfromlast
- (7 * wholeweeks
) + lastday
) > 7 )
1432 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date
.Format("%d %m %Y"), *day
, *week
);
1438 // ----------------------------------------------------------------------------
1440 // ----------------------------------------------------------------------------
1442 void wxCalendarCtrl::OnDClick(wxMouseEvent
& event
)
1444 if ( HitTest(event
.GetPosition()) != wxCAL_HITTEST_DAY
)
1450 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1454 void wxCalendarCtrl::OnClick(wxMouseEvent
& event
)
1457 wxDateTime::WeekDay wday
;
1458 switch ( HitTest(event
.GetPosition(), &date
, &wday
) )
1460 case wxCAL_HITTEST_DAY
:
1461 if ( IsDateInRange(date
) )
1465 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED
,
1466 wxEVT_CALENDAR_SEL_CHANGED
);
1470 case wxCAL_HITTEST_HEADER
:
1472 wxCalendarEvent
event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED
);
1473 event
.m_wday
= wday
;
1474 (void)GetEventHandler()->ProcessEvent(event
);
1478 case wxCAL_HITTEST_DECMONTH
:
1479 case wxCAL_HITTEST_INCMONTH
:
1480 case wxCAL_HITTEST_SURROUNDING_WEEK
:
1481 SetDateAndNotify(date
); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1485 wxFAIL_MSG(_T("unknown hittest code"));
1488 case wxCAL_HITTEST_NOWHERE
:
1494 wxCalendarHitTestResult
wxCalendarCtrl::HitTest(const wxPoint
& pos
,
1496 wxDateTime::WeekDay
*wd
)
1502 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1503 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
1507 // we need to find out if the hit is on left arrow, on month or on right arrow
1509 if ( wxRegion(m_leftArrowRect
).Contains(pos
) == wxInRegion
)
1513 if ( IsDateInRange(m_date
- wxDateSpan::Month()) )
1515 *date
= m_date
- wxDateSpan::Month();
1519 *date
= GetLowerDateLimit();
1523 return wxCAL_HITTEST_DECMONTH
;
1526 if ( wxRegion(m_rightArrowRect
).Contains(pos
) == wxInRegion
)
1530 if ( IsDateInRange(m_date
+ wxDateSpan::Month()) )
1532 *date
= m_date
+ wxDateSpan::Month();
1536 *date
= GetUpperDateLimit();
1540 return wxCAL_HITTEST_INCMONTH
;
1545 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1547 int wday
= pos
.x
/ m_widthCol
;
1548 // if ( y < m_heightRow )
1549 if ( y
< (m_heightRow
+ m_rowOffset
) )
1551 if ( y
> m_rowOffset
)
1555 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST
)
1557 wday
= wday
== 6 ? 0 : wday
+ 1;
1560 *wd
= (wxDateTime::WeekDay
)wday
;
1563 return wxCAL_HITTEST_HEADER
;
1567 return wxCAL_HITTEST_NOWHERE
;
1571 // int week = (y - m_heightRow) / m_heightRow;
1572 int week
= (y
- (m_heightRow
+ m_rowOffset
)) / m_heightRow
;
1573 if ( week
>= 6 || wday
>= 7 )
1575 return wxCAL_HITTEST_NOWHERE
;
1578 wxDateTime dt
= GetStartDate() + wxDateSpan::Days(7*week
+ wday
);
1580 if ( IsDateShown(dt
) )
1585 if ( dt
.GetMonth() == m_date
.GetMonth() )
1588 return wxCAL_HITTEST_DAY
;
1592 return wxCAL_HITTEST_SURROUNDING_WEEK
;
1597 return wxCAL_HITTEST_NOWHERE
;
1601 // ----------------------------------------------------------------------------
1602 // subcontrols events handling
1603 // ----------------------------------------------------------------------------
1605 void wxCalendarCtrl::OnMonthChange(wxCommandEvent
& event
)
1607 wxDateTime::Tm tm
= m_date
.GetTm();
1609 wxDateTime::Month mon
= (wxDateTime::Month
)event
.GetInt();
1610 if ( tm
.mday
> wxDateTime::GetNumberOfDays(mon
, tm
.year
) )
1612 tm
.mday
= wxDateTime::GetNumberOfDays(mon
, tm
.year
);
1615 wxDateTime target
= wxDateTime(tm
.mday
, mon
, tm
.year
);
1617 ChangeMonth(&target
);
1618 SetDateAndNotify(target
);
1621 void wxCalendarCtrl::OnYearChange(wxCommandEvent
& event
)
1623 int year
= (int)event
.GetInt();
1624 if ( year
== INT_MIN
)
1626 // invalid year in the spin control, ignore it
1630 wxDateTime::Tm tm
= m_date
.GetTm();
1632 if ( tm
.mday
> wxDateTime::GetNumberOfDays(tm
.mon
, year
) )
1634 tm
.mday
= wxDateTime::GetNumberOfDays(tm
.mon
, year
);
1637 wxDateTime target
= wxDateTime(tm
.mday
, tm
.mon
, year
);
1639 if ( ChangeYear(&target
) )
1641 SetDateAndNotify(target
);
1645 // In this case we don't want to change the date. That would put us
1646 // inside the same year but a strange number of months forward/back..
1647 m_spinYear
->SetValue(target
.GetYear());
1651 // ----------------------------------------------------------------------------
1652 // keyboard interface
1653 // ----------------------------------------------------------------------------
1655 void wxCalendarCtrl::OnChar(wxKeyEvent
& event
)
1658 switch ( event
.GetKeyCode() )
1662 target
= m_date
+ wxDateSpan::Year();
1663 if ( ChangeYear(&target
) )
1665 SetDateAndNotify(target
);
1671 target
= m_date
- wxDateSpan::Year();
1672 if ( ChangeYear(&target
) )
1674 SetDateAndNotify(target
);
1679 target
= m_date
- wxDateSpan::Month();
1680 ChangeMonth(&target
);
1681 SetDateAndNotify(target
); // always
1685 target
= m_date
+ wxDateSpan::Month();
1686 ChangeMonth(&target
);
1687 SetDateAndNotify(target
); // always
1691 if ( event
.ControlDown() )
1693 target
= wxDateTime(m_date
).SetToNextWeekDay(
1694 GetWindowStyle() & wxCAL_MONDAY_FIRST
1695 ? wxDateTime::Sun
: wxDateTime::Sat
);
1696 if ( !IsDateInRange(target
) )
1698 target
= GetUpperDateLimit();
1700 SetDateAndNotify(target
);
1703 SetDateAndNotify(m_date
+ wxDateSpan::Day());
1707 if ( event
.ControlDown() )
1709 target
= wxDateTime(m_date
).SetToPrevWeekDay(
1710 GetWindowStyle() & wxCAL_MONDAY_FIRST
1711 ? wxDateTime::Mon
: wxDateTime::Sun
);
1712 if ( !IsDateInRange(target
) )
1714 target
= GetLowerDateLimit();
1716 SetDateAndNotify(target
);
1719 SetDateAndNotify(m_date
- wxDateSpan::Day());
1723 SetDateAndNotify(m_date
- wxDateSpan::Week());
1727 SetDateAndNotify(m_date
+ wxDateSpan::Week());
1731 if ( event
.ControlDown() )
1732 SetDateAndNotify(wxDateTime::Today());
1734 SetDateAndNotify(wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear()));
1738 SetDateAndNotify(wxDateTime(m_date
).SetToLastMonthDay());
1742 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1750 // ----------------------------------------------------------------------------
1751 // holidays handling
1752 // ----------------------------------------------------------------------------
1754 void wxCalendarCtrl::EnableHolidayDisplay(bool display
)
1756 long style
= GetWindowStyle();
1758 style
|= wxCAL_SHOW_HOLIDAYS
;
1760 style
&= ~wxCAL_SHOW_HOLIDAYS
;
1762 SetWindowStyle(style
);
1767 ResetHolidayAttrs();
1772 void wxCalendarCtrl::SetHolidayAttrs()
1774 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS
)
1776 ResetHolidayAttrs();
1778 wxDateTime::Tm tm
= m_date
.GetTm();
1779 wxDateTime
dtStart(1, tm
.mon
, tm
.year
),
1780 dtEnd
= dtStart
.GetLastMonthDay();
1782 wxDateTimeArray hol
;
1783 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart
, dtEnd
, hol
);
1785 size_t count
= hol
.GetCount();
1786 for ( size_t n
= 0; n
< count
; n
++ )
1788 SetHoliday(hol
[n
].GetDay());
1793 void wxCalendarCtrl::SetHoliday(size_t day
)
1795 wxCHECK_RET( day
> 0 && day
< 32, _T("invalid day in SetHoliday") );
1797 wxCalendarDateAttr
*attr
= GetAttr(day
);
1800 attr
= new wxCalendarDateAttr
;
1803 attr
->SetHoliday(true);
1805 // can't use SetAttr() because it would delete this pointer
1806 m_attrs
[day
- 1] = attr
;
1809 void wxCalendarCtrl::ResetHolidayAttrs()
1811 for ( size_t day
= 0; day
< 31; day
++ )
1815 m_attrs
[day
]->SetHoliday(false);
1823 wxCalendarCtrl::GetClassDefaultAttributes(wxWindowVariant variant
)
1825 // Use the same color scheme as wxListBox
1826 return wxListBox::GetClassDefaultAttributes(variant
);
1829 #endif // wxUSE_CALENDARCTRL