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/stattext.h"
37 #include "wx/textctrl.h"
40 #if wxUSE_CALENDARCTRL
42 #include "wx/spinctrl.h"
44 #include "wx/calctrl.h"
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 class wxMonthComboBox
: public wxComboBox
55 wxMonthComboBox(wxCalendarCtrl
*cal
);
57 void OnMonthChange(wxCommandEvent
& event
) { m_cal
->OnMonthChange(event
); }
60 wxCalendarCtrl
*m_cal
;
63 DECLARE_NO_COPY_CLASS(wxMonthComboBox
)
66 class wxYearSpinCtrl
: public wxSpinCtrl
69 wxYearSpinCtrl(wxCalendarCtrl
*cal
);
71 void OnYearTextChange(wxCommandEvent
& event
)
73 m_cal
->SetUserChangedYear();
74 m_cal
->OnYearChange(event
);
76 void OnYearChange(wxSpinEvent
& event
) { m_cal
->OnYearChange(event
); }
79 wxCalendarCtrl
*m_cal
;
82 DECLARE_NO_COPY_CLASS(wxYearSpinCtrl
)
85 // ----------------------------------------------------------------------------
87 // ----------------------------------------------------------------------------
89 BEGIN_EVENT_TABLE(wxCalendarCtrl
, wxControl
)
90 EVT_PAINT(wxCalendarCtrl::OnPaint
)
92 EVT_CHAR(wxCalendarCtrl::OnChar
)
94 EVT_LEFT_DOWN(wxCalendarCtrl::OnClick
)
95 EVT_LEFT_DCLICK(wxCalendarCtrl::OnDClick
)
98 BEGIN_EVENT_TABLE(wxMonthComboBox
, wxComboBox
)
99 EVT_COMBOBOX(-1, wxMonthComboBox::OnMonthChange
)
102 BEGIN_EVENT_TABLE(wxYearSpinCtrl
, wxSpinCtrl
)
103 EVT_TEXT(-1, wxYearSpinCtrl::OnYearTextChange
)
104 EVT_SPINCTRL(-1, wxYearSpinCtrl::OnYearChange
)
107 #if wxUSE_EXTENDED_RTTI
108 WX_DEFINE_FLAGS( wxCalendarCtrlStyle
)
110 wxBEGIN_FLAGS( wxCalendarCtrlStyle
)
111 // new style border flags, we put them first to
112 // use them for streaming out
113 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
114 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
115 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
116 wxFLAGS_MEMBER(wxBORDER_RAISED
)
117 wxFLAGS_MEMBER(wxBORDER_STATIC
)
118 wxFLAGS_MEMBER(wxBORDER_NONE
)
120 // old style border flags
121 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
122 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
123 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
124 wxFLAGS_MEMBER(wxRAISED_BORDER
)
125 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
126 wxFLAGS_MEMBER(wxBORDER
)
128 // standard window styles
129 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
130 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
131 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
132 wxFLAGS_MEMBER(wxWANTS_CHARS
)
133 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
134 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
135 wxFLAGS_MEMBER(wxVSCROLL
)
136 wxFLAGS_MEMBER(wxHSCROLL
)
138 wxFLAGS_MEMBER(wxCAL_SUNDAY_FIRST
)
139 wxFLAGS_MEMBER(wxCAL_MONDAY_FIRST
)
140 wxFLAGS_MEMBER(wxCAL_SHOW_HOLIDAYS
)
141 wxFLAGS_MEMBER(wxCAL_NO_YEAR_CHANGE
)
142 wxFLAGS_MEMBER(wxCAL_NO_MONTH_CHANGE
)
143 wxFLAGS_MEMBER(wxCAL_SEQUENTIAL_MONTH_SELECTION
)
144 wxFLAGS_MEMBER(wxCAL_SHOW_SURROUNDING_WEEKS
)
146 wxEND_FLAGS( wxCalendarCtrlStyle
)
148 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCalendarCtrl
, wxControl
,"wx/calctrl.h")
150 wxBEGIN_PROPERTIES_TABLE(wxCalendarCtrl
)
151 wxEVENT_RANGE_PROPERTY( Updated
, wxEVT_CALENDAR_SEL_CHANGED
, wxEVT_CALENDAR_WEEKDAY_CLICKED
, wxCalendarEvent
)
152 wxHIDE_PROPERTY( Children
)
153 wxPROPERTY( Date
,wxDateTime
, SetDate
, GetDate
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
154 wxPROPERTY_FLAGS( WindowStyle
, wxCalendarCtrlStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
155 wxEND_PROPERTIES_TABLE()
157 wxBEGIN_HANDLERS_TABLE(wxCalendarCtrl
)
158 wxEND_HANDLERS_TABLE()
160 wxCONSTRUCTOR_6( wxCalendarCtrl
, wxWindow
* , Parent
, wxWindowID
, Id
, wxDateTime
, Date
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
162 IMPLEMENT_DYNAMIC_CLASS(wxCalendarCtrl
, wxControl
)
164 IMPLEMENT_DYNAMIC_CLASS(wxCalendarEvent
, wxCommandEvent
)
166 // ----------------------------------------------------------------------------
168 // ----------------------------------------------------------------------------
170 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_SEL_CHANGED
)
171 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DAY_CHANGED
)
172 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_MONTH_CHANGED
)
173 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_YEAR_CHANGED
)
174 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DOUBLECLICKED
)
175 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_WEEKDAY_CLICKED
)
177 // ============================================================================
179 // ============================================================================
181 // ----------------------------------------------------------------------------
182 // wxMonthComboBox and wxYearSpinCtrl
183 // ----------------------------------------------------------------------------
185 wxMonthComboBox::wxMonthComboBox(wxCalendarCtrl
*cal
)
186 : wxComboBox(cal
->GetParent(), -1,
191 wxCB_READONLY
| wxCLIP_SIBLINGS
)
196 for ( m
= wxDateTime::Jan
; m
< wxDateTime::Inv_Month
; wxNextMonth(m
) )
198 Append(wxDateTime::GetMonthName(m
));
201 SetSelection(m_cal
->GetDate().GetMonth());
202 SetSize(-1, -1, -1, -1, wxSIZE_AUTO_WIDTH
|wxSIZE_AUTO_HEIGHT
);
205 wxYearSpinCtrl::wxYearSpinCtrl(wxCalendarCtrl
*cal
)
206 : wxSpinCtrl(cal
->GetParent(), -1,
207 cal
->GetDate().Format(_T("%Y")),
210 wxSP_ARROW_KEYS
| wxCLIP_SIBLINGS
,
211 -4300, 10000, cal
->GetDate().GetYear())
217 // ----------------------------------------------------------------------------
219 // ----------------------------------------------------------------------------
221 wxCalendarCtrl::wxCalendarCtrl(wxWindow
*parent
,
223 const wxDateTime
& date
,
227 const wxString
& name
)
231 (void)Create(parent
, id
, date
, pos
, size
, style
, name
);
234 void wxCalendarCtrl::Init()
239 m_staticMonth
= NULL
;
241 m_userChangedYear
= FALSE
;
246 wxDateTime::WeekDay wd
;
247 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
249 m_weekdays
[wd
] = wxDateTime::GetWeekDayName(wd
, wxDateTime::Name_Abbr
);
252 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
257 m_colHighlightFg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
258 m_colHighlightBg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
);
260 m_colHolidayFg
= *wxRED
;
261 // don't set m_colHolidayBg - by default, same as our bg colour
263 m_colHeaderFg
= *wxBLUE
;
264 m_colHeaderBg
= *wxLIGHT_GREY
;
267 bool wxCalendarCtrl::Create(wxWindow
*parent
,
269 const wxDateTime
& date
,
273 const wxString
& name
)
275 if ( !wxControl::Create(parent
, id
, pos
, size
,
276 style
| wxCLIP_CHILDREN
| wxWANTS_CHARS
,
277 wxDefaultValidator
, name
) )
282 // needed to get the arrow keys normally used for the dialog navigation
283 SetWindowStyle(style
| wxWANTS_CHARS
);
285 m_date
= date
.IsValid() ? date
: wxDateTime::Today();
287 m_lowdate
= wxDefaultDateTime
;
288 m_highdate
= wxDefaultDateTime
;
290 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
292 m_spinYear
= new wxYearSpinCtrl(this);
293 m_staticYear
= new wxStaticText(GetParent(), -1, m_date
.Format(_T("%Y")),
294 wxDefaultPosition
, wxDefaultSize
,
297 m_comboMonth
= new wxMonthComboBox(this);
298 m_staticMonth
= new wxStaticText(GetParent(), -1, m_date
.Format(_T("%B")),
299 wxDefaultPosition
, wxDefaultSize
,
303 ShowCurrentControls();
306 if ( size
.x
== -1 || size
.y
== -1 )
308 sizeReal
= DoGetBestSize();
319 // we need to set the position as well because the main control position
320 // is not the same as the one specified in pos if we have the controls
322 SetSize(pos
.x
, pos
.y
, sizeReal
.x
, sizeReal
.y
);
324 SetBackgroundColour(*wxWHITE
);
325 SetFont(*wxSWISS_FONT
);
332 wxCalendarCtrl::~wxCalendarCtrl()
334 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
340 // ----------------------------------------------------------------------------
341 // forward wxWin functions to subcontrols
342 // ----------------------------------------------------------------------------
344 bool wxCalendarCtrl::Destroy()
347 m_staticYear
->Destroy();
349 m_spinYear
->Destroy();
351 m_comboMonth
->Destroy();
353 m_staticMonth
->Destroy();
358 m_staticMonth
= NULL
;
360 return wxControl::Destroy();
363 bool wxCalendarCtrl::Show(bool show
)
365 if ( !wxControl::Show(show
) )
370 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
372 if ( GetMonthControl() )
374 GetMonthControl()->Show(show
);
375 GetYearControl()->Show(show
);
382 bool wxCalendarCtrl::Enable(bool enable
)
384 if ( !wxControl::Enable(enable
) )
389 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
391 GetMonthControl()->Enable(enable
);
392 GetYearControl()->Enable(enable
);
398 // ----------------------------------------------------------------------------
399 // enable/disable month/year controls
400 // ----------------------------------------------------------------------------
402 void wxCalendarCtrl::ShowCurrentControls()
404 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
406 if ( AllowMonthChange() )
408 m_comboMonth
->Show();
409 m_staticMonth
->Hide();
411 if ( AllowYearChange() )
414 m_staticYear
->Hide();
422 m_comboMonth
->Hide();
423 m_staticMonth
->Show();
426 // year change not allowed here
428 m_staticYear
->Show();
432 wxControl
*wxCalendarCtrl::GetMonthControl() const
434 return AllowMonthChange() ? (wxControl
*)m_comboMonth
: (wxControl
*)m_staticMonth
;
437 wxControl
*wxCalendarCtrl::GetYearControl() const
439 return AllowYearChange() ? (wxControl
*)m_spinYear
: (wxControl
*)m_staticYear
;
442 void wxCalendarCtrl::EnableYearChange(bool enable
)
444 if ( enable
!= AllowYearChange() )
446 long style
= GetWindowStyle();
448 style
&= ~wxCAL_NO_YEAR_CHANGE
;
450 style
|= wxCAL_NO_YEAR_CHANGE
;
451 SetWindowStyle(style
);
453 ShowCurrentControls();
454 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
461 void wxCalendarCtrl::EnableMonthChange(bool enable
)
463 if ( enable
!= AllowMonthChange() )
465 long style
= GetWindowStyle();
467 style
&= ~wxCAL_NO_MONTH_CHANGE
;
469 style
|= wxCAL_NO_MONTH_CHANGE
;
470 SetWindowStyle(style
);
472 ShowCurrentControls();
473 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
480 // ----------------------------------------------------------------------------
482 // ----------------------------------------------------------------------------
484 bool wxCalendarCtrl::SetDate(const wxDateTime
& date
)
488 bool sameMonth
= m_date
.GetMonth() == date
.GetMonth(),
489 sameYear
= m_date
.GetYear() == date
.GetYear();
491 if ( IsDateInRange(date
) )
493 if ( sameMonth
&& sameYear
)
495 // just change the day
500 if ( AllowMonthChange() && (AllowYearChange() || sameYear
) )
505 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
507 // update the controls
508 m_comboMonth
->SetSelection(m_date
.GetMonth());
510 if ( AllowYearChange() )
512 if ( !m_userChangedYear
)
513 m_spinYear
->SetValue(m_date
.Format(_T("%Y")));
517 // as the month changed, holidays did too
520 // update the calendar
531 m_userChangedYear
= FALSE
;
536 void wxCalendarCtrl::ChangeDay(const wxDateTime
& date
)
538 if ( m_date
!= date
)
540 // we need to refresh the row containing the old date and the one
541 // containing the new one
542 wxDateTime dateOld
= m_date
;
545 RefreshDate(dateOld
);
547 // if the date is in the same row, it was already drawn correctly
548 if ( GetWeek(m_date
) != GetWeek(dateOld
) )
555 void wxCalendarCtrl::SetDateAndNotify(const wxDateTime
& date
)
557 wxDateTime::Tm tm1
= m_date
.GetTm(),
561 if ( tm1
.year
!= tm2
.year
)
562 type
= wxEVT_CALENDAR_YEAR_CHANGED
;
563 else if ( tm1
.mon
!= tm2
.mon
)
564 type
= wxEVT_CALENDAR_MONTH_CHANGED
;
565 else if ( tm1
.mday
!= tm2
.mday
)
566 type
= wxEVT_CALENDAR_DAY_CHANGED
;
572 GenerateEvents(type
, wxEVT_CALENDAR_SEL_CHANGED
);
576 // ----------------------------------------------------------------------------
578 // ----------------------------------------------------------------------------
580 bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
584 if ( !(date
.IsValid()) || ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : TRUE
) )
596 bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
600 if ( !(date
.IsValid()) || ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : TRUE
) )
612 bool wxCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
/* = wxDefaultDateTime */, const wxDateTime
& upperdate
/* = wxDefaultDateTime */)
617 ( !( lowerdate
.IsValid() ) || ( ( upperdate
.IsValid() ) ? ( lowerdate
<= upperdate
) : TRUE
) ) &&
618 ( !( upperdate
.IsValid() ) || ( ( lowerdate
.IsValid() ) ? ( upperdate
>= lowerdate
) : TRUE
) ) )
620 m_lowdate
= lowerdate
;
621 m_highdate
= upperdate
;
631 // ----------------------------------------------------------------------------
633 // ----------------------------------------------------------------------------
635 wxDateTime
wxCalendarCtrl::GetStartDate() const
637 wxDateTime::Tm tm
= m_date
.GetTm();
639 wxDateTime date
= wxDateTime(1, tm
.mon
, tm
.year
);
642 date
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
643 ? wxDateTime::Mon
: wxDateTime::Sun
);
645 if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
)
647 // We want to offset the calendar if we start on the first..
648 if ( date
.GetDay() == 1 )
650 date
-= wxDateSpan::Week();
657 bool wxCalendarCtrl::IsDateShown(const wxDateTime
& date
) const
659 if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
661 return date
.GetMonth() == m_date
.GetMonth();
669 bool wxCalendarCtrl::IsDateInRange(const wxDateTime
& date
) const
671 // Check if the given date is in the range specified
672 return ( ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : TRUE
)
673 && ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : TRUE
) );
676 bool wxCalendarCtrl::ChangeYear(wxDateTime
* target
) const
680 if ( !(IsDateInRange(*target
)) )
682 if ( target
->GetYear() < m_date
.GetYear() )
684 if ( target
->GetYear() >= GetLowerDateLimit().GetYear() )
686 *target
= GetLowerDateLimit();
696 if ( target
->GetYear() <= GetUpperDateLimit().GetYear() )
698 *target
= GetUpperDateLimit();
715 bool wxCalendarCtrl::ChangeMonth(wxDateTime
* target
) const
719 if ( !(IsDateInRange(*target
)) )
723 if ( target
->GetMonth() < m_date
.GetMonth() )
725 *target
= GetLowerDateLimit();
729 *target
= GetUpperDateLimit();
736 size_t wxCalendarCtrl::GetWeek(const wxDateTime
& date
) const
738 size_t retval
= date
.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
739 ? wxDateTime::Monday_First
740 : wxDateTime::Sunday_First
);
742 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
744 // we need to offset an extra week if we "start" on the 1st of the month
745 wxDateTime::Tm tm
= date
.GetTm();
747 wxDateTime datetest
= wxDateTime(1, tm
.mon
, tm
.year
);
750 datetest
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
751 ? wxDateTime::Mon
: wxDateTime::Sun
);
753 if ( datetest
.GetDay() == 1 )
762 // ----------------------------------------------------------------------------
764 // ----------------------------------------------------------------------------
766 // this is a composite control and it must arrange its parts each time its
767 // size or position changes: the combobox and spinctrl are along the top of
768 // the available area and the calendar takes up therest of the space
770 // the static controls are supposed to be always smaller than combo/spin so we
771 // always use the latter for size calculations and position the static to take
774 // the constants used for the layout
775 #define VERT_MARGIN 5 // distance between combo and calendar
777 #define HORZ_MARGIN 5 // spin
779 #define HORZ_MARGIN 15 // spin
781 wxSize
wxCalendarCtrl::DoGetBestSize() const
783 // calc the size of the calendar
784 ((wxCalendarCtrl
*)this)->RecalcGeometry(); // const_cast
786 wxCoord width
= 7*m_widthCol
,
787 height
= 7*m_heightRow
+ m_rowOffset
+ VERT_MARGIN
;
789 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
791 // the combobox doesn't report its height correctly (it returns the
792 // height including the drop down list) so don't use it
793 height
+= m_spinYear
->GetBestSize().y
;
796 if ( !HasFlag(wxBORDER_NONE
) )
798 // the border would clip the last line otherwise
803 return wxSize(width
, height
);
806 void wxCalendarCtrl::DoSetSize(int x
, int y
,
807 int width
, int height
,
810 wxControl::DoSetSize(x
, y
, width
, height
, sizeFlags
);
813 void wxCalendarCtrl::DoMoveWindow(int x
, int y
, int width
, int height
)
817 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
819 wxSize sizeCombo
= m_comboMonth
->GetSize();
820 wxSize sizeStatic
= m_staticMonth
->GetSize();
821 wxSize sizeSpin
= m_spinYear
->GetSize();
822 int dy
= (sizeCombo
.y
- sizeStatic
.y
) / 2;
824 In the calender the size of the combobox for the year
825 is just defined by a margin from the month combobox to
826 the left border. While in wxUniv the year control can't
827 show all 4 digits, in wxMsw it show almost twice as
828 much. Instead the year should use it's best size and be
829 left aligned to the calendar. Just in case the month in
830 any language is longer than it has space in the
831 calendar it is shortend.This way the year always can
834 This patch relies on the fact that a combobox has a
835 good best size implementation. This is not the case
836 with wxMSW but I don't know why.
841 #ifdef __WXUNIVERSAL__
842 if (sizeCombo
.x
+ HORZ_MARGIN
- sizeSpin
.x
> width
)
844 m_comboMonth
->SetSize(x
, y
, width
- HORZ_MARGIN
- sizeSpin
.x
, sizeCombo
.y
);
848 m_comboMonth
->Move(x
, y
);
850 m_staticMonth
->Move(x
, y
+ dy
);
851 m_spinYear
->Move(x
+ width
- sizeSpin
.x
, y
);
852 m_staticYear
->Move(x
+ width
- sizeSpin
.x
, y
+ dy
);
854 m_comboMonth
->Move(x
, y
);
855 m_staticMonth
->SetSize(x
, y
+ dy
, sizeCombo
.x
, sizeStatic
.y
);
857 int xDiff
= sizeCombo
.x
+ HORZ_MARGIN
;
859 m_spinYear
->SetSize(x
+ xDiff
, y
, width
- xDiff
, sizeCombo
.y
);
860 m_staticYear
->SetSize(x
+ xDiff
, y
+ dy
, width
- xDiff
, sizeStatic
.y
);
862 yDiff
= wxMax(sizeSpin
.y
, sizeCombo
.y
) + VERT_MARGIN
;
864 else // no controls on the top
869 wxControl::DoMoveWindow(x
, y
+ yDiff
, width
, height
- yDiff
);
872 void wxCalendarCtrl::DoGetPosition(int *x
, int *y
) const
874 wxControl::DoGetPosition(x
, y
);
876 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
878 // our real top corner is not in this position
881 *y
-= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
886 void wxCalendarCtrl::DoGetSize(int *width
, int *height
) const
888 wxControl::DoGetSize(width
, height
);
890 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
892 // our real height is bigger
893 if ( height
&& GetMonthControl())
895 *height
+= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
900 void wxCalendarCtrl::RecalcGeometry()
902 if ( m_widthCol
!= 0 )
909 // determine the column width (we assume that the weekday names are always
910 // wider (in any language) than the numbers)
912 wxDateTime::WeekDay wd
;
913 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
916 dc
.GetTextExtent(m_weekdays
[wd
], &width
, &m_heightRow
);
917 if ( width
> m_widthCol
)
923 // leave some margins
927 m_rowOffset
= (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) ? m_heightRow
: 0; // conditional in relation to style
930 // ----------------------------------------------------------------------------
932 // ----------------------------------------------------------------------------
934 void wxCalendarCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
))
943 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
944 m_date
.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
950 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
952 // draw the sequential month-selector
954 dc
.SetBackgroundMode(wxTRANSPARENT
);
955 dc
.SetTextForeground(*wxBLACK
);
956 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
957 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
958 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
960 // Get extent of month-name + year
961 wxCoord monthw
, monthh
;
962 wxString headertext
= m_date
.Format(wxT("%B %Y"));
963 dc
.GetTextExtent(headertext
, &monthw
, &monthh
);
965 // draw month-name centered above weekdays
966 wxCoord monthx
= ((m_widthCol
* 7) - monthw
) / 2;
967 wxCoord monthy
= ((m_heightRow
- monthh
) / 2) + y
;
968 dc
.DrawText(headertext
, monthx
, monthy
);
970 // calculate the "month-arrows"
971 wxPoint leftarrow
[3];
972 wxPoint rightarrow
[3];
974 int arrowheight
= monthh
/ 2;
976 leftarrow
[0] = wxPoint(0, arrowheight
/ 2);
977 leftarrow
[1] = wxPoint(arrowheight
/ 2, 0);
978 leftarrow
[2] = wxPoint(arrowheight
/ 2, arrowheight
- 1);
980 rightarrow
[0] = wxPoint(0, 0);
981 rightarrow
[1] = wxPoint(arrowheight
/ 2, arrowheight
/ 2);
982 rightarrow
[2] = wxPoint(0, arrowheight
- 1);
984 // draw the "month-arrows"
986 wxCoord arrowy
= (m_heightRow
- arrowheight
) / 2;
987 wxCoord larrowx
= (m_widthCol
- (arrowheight
/ 2)) / 2;
988 wxCoord rarrowx
= ((m_widthCol
- (arrowheight
/ 2)) / 2) + m_widthCol
*6;
989 m_leftArrowRect
= wxRect(0, 0, 0, 0);
990 m_rightArrowRect
= wxRect(0, 0, 0, 0);
992 if ( AllowMonthChange() )
994 wxDateTime ldpm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) - wxDateSpan::Day(); // last day prev month
995 // Check if range permits change
996 if ( IsDateInRange(ldpm
) && ( ( ldpm
.GetYear() == m_date
.GetYear() ) ? TRUE
: AllowYearChange() ) )
998 m_leftArrowRect
= wxRect(larrowx
- 3, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
999 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1000 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1001 dc
.DrawPolygon(3, leftarrow
, larrowx
, arrowy
, wxWINDING_RULE
);
1002 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1003 dc
.DrawRectangle(m_leftArrowRect
);
1005 wxDateTime fdnm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) + wxDateSpan::Month(); // first day next month
1006 if ( IsDateInRange(fdnm
) && ( ( fdnm
.GetYear() == m_date
.GetYear() ) ? TRUE
: AllowYearChange() ) )
1008 m_rightArrowRect
= wxRect(rarrowx
- 4, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1009 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1010 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1011 dc
.DrawPolygon(3, rightarrow
, rarrowx
, arrowy
, wxWINDING_RULE
);
1012 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1013 dc
.DrawRectangle(m_rightArrowRect
);
1020 // first draw the week days
1021 if ( IsExposed(0, y
, 7*m_widthCol
, m_heightRow
) )
1024 wxLogDebug("painting the header");
1027 dc
.SetBackgroundMode(wxTRANSPARENT
);
1028 dc
.SetTextForeground(m_colHeaderFg
);
1029 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
1030 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
1031 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
1033 bool startOnMonday
= (GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1034 for ( size_t wd
= 0; wd
< 7; wd
++ )
1037 if ( startOnMonday
)
1038 n
= wd
== 6 ? 0 : wd
+ 1;
1042 dc
.GetTextExtent(m_weekdays
[n
], &dayw
, &dayh
);
1043 dc
.DrawText(m_weekdays
[n
], (wd
*m_widthCol
) + ((m_widthCol
- dayw
) / 2), y
); // center the day-name
1047 // then the calendar itself
1048 dc
.SetTextForeground(*wxBLACK
);
1049 //dc.SetFont(*wxNORMAL_FONT);
1052 wxDateTime date
= GetStartDate();
1055 wxLogDebug("starting calendar from %s\n",
1056 date
.Format("%a %d-%m-%Y %H:%M:%S").c_str());
1059 dc
.SetBackgroundMode(wxSOLID
);
1060 for ( size_t nWeek
= 1; nWeek
<= 6; nWeek
++, y
+= m_heightRow
)
1062 // if the update region doesn't intersect this row, don't paint it
1063 if ( !IsExposed(0, y
, 7*m_widthCol
, m_heightRow
- 1) )
1065 date
+= wxDateSpan::Week();
1071 wxLogDebug("painting week %d at y = %d\n", nWeek
, y
);
1074 for ( size_t wd
= 0; wd
< 7; wd
++ )
1076 if ( IsDateShown(date
) )
1078 // don't use wxDate::Format() which prepends 0s
1079 unsigned int day
= date
.GetDay();
1080 wxString dayStr
= wxString::Format(_T("%u"), day
);
1082 dc
.GetTextExtent(dayStr
, &width
, (wxCoord
*)NULL
);
1084 bool changedColours
= FALSE
,
1085 changedFont
= FALSE
;
1088 wxCalendarDateAttr
*attr
= NULL
;
1090 if ( date
.GetMonth() != m_date
.GetMonth() || !IsDateInRange(date
) )
1092 // surrounding week or out-of-range
1094 dc
.SetTextForeground(*wxLIGHT_GREY
);
1095 changedColours
= TRUE
;
1099 isSel
= date
.IsSameDate(m_date
);
1100 attr
= m_attrs
[day
- 1];
1104 dc
.SetTextForeground(m_colHighlightFg
);
1105 dc
.SetTextBackground(m_colHighlightBg
);
1107 changedColours
= TRUE
;
1111 wxColour colFg
, colBg
;
1113 if ( attr
->IsHoliday() )
1115 colFg
= m_colHolidayFg
;
1116 colBg
= m_colHolidayBg
;
1120 colFg
= attr
->GetTextColour();
1121 colBg
= attr
->GetBackgroundColour();
1126 dc
.SetTextForeground(colFg
);
1127 changedColours
= TRUE
;
1132 dc
.SetTextBackground(colBg
);
1133 changedColours
= TRUE
;
1136 if ( attr
->HasFont() )
1138 dc
.SetFont(attr
->GetFont());
1144 wxCoord x
= wd
*m_widthCol
+ (m_widthCol
- width
) / 2;
1145 dc
.DrawText(dayStr
, x
, y
+ 1);
1147 if ( !isSel
&& attr
&& attr
->HasBorder() )
1150 if ( attr
->HasBorderColour() )
1152 colBorder
= attr
->GetBorderColour();
1156 colBorder
= m_foregroundColour
;
1159 wxPen
pen(colBorder
, 1, wxSOLID
);
1161 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1163 switch ( attr
->GetBorder() )
1165 case wxCAL_BORDER_SQUARE
:
1166 dc
.DrawRectangle(x
- 2, y
,
1167 width
+ 4, m_heightRow
);
1170 case wxCAL_BORDER_ROUND
:
1171 dc
.DrawEllipse(x
- 2, y
,
1172 width
+ 4, m_heightRow
);
1176 wxFAIL_MSG(_T("unknown border type"));
1180 if ( changedColours
)
1182 dc
.SetTextForeground(m_foregroundColour
);
1183 dc
.SetTextBackground(m_backgroundColour
);
1191 //else: just don't draw it
1193 date
+= wxDateSpan::Day();
1197 // Greying out out-of-range background
1198 bool showSurrounding
= (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) != 0;
1200 date
= ( showSurrounding
) ? GetStartDate() : wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear());
1201 if ( !IsDateInRange(date
) )
1203 wxDateTime firstOOR
= GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1205 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1206 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1208 HighlightRange(&dc
, date
, firstOOR
, wxTRANSPARENT_PEN
, &oorbrush
);
1211 date
= ( showSurrounding
) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear());
1212 if ( !IsDateInRange(date
) )
1214 wxDateTime firstOOR
= GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1216 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1217 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1219 HighlightRange(&dc
, firstOOR
, date
, wxTRANSPARENT_PEN
, &oorbrush
);
1223 wxLogDebug("+++ finished painting");
1227 void wxCalendarCtrl::RefreshDate(const wxDateTime
& date
)
1233 // always refresh the whole row at once because our OnPaint() will draw
1234 // the whole row anyhow - and this allows the small optimisation in
1235 // OnClick() below to work
1238 rect
.y
= (m_heightRow
* GetWeek(date
)) + m_rowOffset
;
1240 rect
.width
= 7*m_widthCol
;
1241 rect
.height
= m_heightRow
;
1244 // VZ: for some reason, the selected date seems to occupy more space under
1245 // MSW - this is probably some bug in the font size calculations, but I
1246 // don't know where exactly. This fix is ugly and leads to more
1247 // refreshes than really needed, but without it the selected days
1248 // leaves even more ugly underscores on screen.
1253 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
1256 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
1259 Refresh(TRUE
, &rect
);
1262 void wxCalendarCtrl::HighlightRange(wxPaintDC
* pDC
, const wxDateTime
& fromdate
, const wxDateTime
& todate
, wxPen
* pPen
, wxBrush
* pBrush
)
1264 // Highlights the given range using pen and brush
1265 // Does nothing if todate < fromdate
1269 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate
.Format("%d %m %Y"), todate
.Format("%d %m %Y"));
1272 if ( todate
>= fromdate
)
1279 // implicit: both dates must be currently shown - checked by GetDateCoord
1280 if ( GetDateCoord(fromdate
, &fd
, &fw
) && GetDateCoord(todate
, &td
, &tw
) )
1283 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd
, fw
, td
, tw
);
1285 if ( ( (tw
- fw
) == 1 ) && ( td
< fd
) )
1287 // special case: interval 7 days or less not in same week
1288 // split in two seperate intervals
1289 wxDateTime tfd
= fromdate
+ wxDateSpan::Days(7-fd
);
1290 wxDateTime ftd
= tfd
+ wxDateSpan::Day();
1292 wxLogDebug("Highlight: Seperate segments");
1295 HighlightRange(pDC
, fromdate
, tfd
, pPen
, pBrush
);
1296 HighlightRange(pDC
, ftd
, todate
, pPen
, pBrush
);
1301 wxPoint corners
[8]; // potentially 8 corners in polygon
1305 // simple case: same week
1307 corners
[0] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
);
1308 corners
[1] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1 ) * m_heightRow
) + m_rowOffset
);
1309 corners
[2] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
);
1310 corners
[3] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
);
1315 // "complex" polygon
1316 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1320 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1321 corners
[cidx
] = wxPoint(0, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1324 corners
[cidx
] = wxPoint(0, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1325 corners
[cidx
] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1329 corners
[cidx
] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1330 corners
[cidx
] = wxPoint(7 * m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1333 corners
[cidx
] = wxPoint(7 * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1339 pDC
->SetBrush(*pBrush
);
1341 pDC
->DrawPolygon(numpoints
, corners
);
1347 wxLogDebug("--- HighlightRange ---");
1351 bool wxCalendarCtrl::GetDateCoord(const wxDateTime
& date
, int *day
, int *week
) const
1356 wxLogDebug("+++ GetDateCoord: (%s) +++", date
.Format("%d %m %Y"));
1359 if ( IsDateShown(date
) )
1361 bool startOnMonday
= ( GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1364 *day
= date
.GetWeekDay();
1366 if ( *day
== 0 ) // sunday
1368 *day
= ( startOnMonday
) ? 7 : 1;
1372 *day
+= ( startOnMonday
) ? 0 : 1;
1375 int targetmonth
= date
.GetMonth() + (12 * date
.GetYear());
1376 int thismonth
= m_date
.GetMonth() + (12 * m_date
.GetYear());
1379 if ( targetmonth
== thismonth
)
1381 *week
= GetWeek(date
);
1385 if ( targetmonth
< thismonth
)
1387 *week
= 1; // trivial
1389 else // targetmonth > thismonth
1395 // get the datecoord of the last day in the month currently shown
1397 wxLogDebug(" +++ LDOM +++");
1399 GetDateCoord(ldcm
.SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear()), &lastday
, &lastweek
);
1401 wxLogDebug(" --- LDOM ---");
1404 wxTimeSpan span
= date
- ldcm
;
1406 int daysfromlast
= span
.GetDays();
1408 wxLogDebug("daysfromlast: %i", daysfromlast
);
1410 if ( daysfromlast
+ lastday
> 7 ) // past week boundary
1412 int wholeweeks
= (daysfromlast
/ 7);
1413 *week
= wholeweeks
+ lastweek
;
1414 if ( (daysfromlast
- (7 * wholeweeks
) + lastday
) > 7 )
1434 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date
.Format("%d %m %Y"), *day
, *week
);
1440 // ----------------------------------------------------------------------------
1442 // ----------------------------------------------------------------------------
1444 void wxCalendarCtrl::OnDClick(wxMouseEvent
& event
)
1446 if ( HitTest(event
.GetPosition()) != wxCAL_HITTEST_DAY
)
1452 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1456 void wxCalendarCtrl::OnClick(wxMouseEvent
& event
)
1459 wxDateTime::WeekDay wday
;
1460 switch ( HitTest(event
.GetPosition(), &date
, &wday
) )
1462 case wxCAL_HITTEST_DAY
:
1463 if ( IsDateInRange(date
) )
1467 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED
,
1468 wxEVT_CALENDAR_SEL_CHANGED
);
1472 case wxCAL_HITTEST_HEADER
:
1474 wxCalendarEvent
event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED
);
1475 event
.m_wday
= wday
;
1476 (void)GetEventHandler()->ProcessEvent(event
);
1480 case wxCAL_HITTEST_DECMONTH
:
1481 case wxCAL_HITTEST_INCMONTH
:
1482 case wxCAL_HITTEST_SURROUNDING_WEEK
:
1483 SetDateAndNotify(date
); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1487 wxFAIL_MSG(_T("unknown hittest code"));
1490 case wxCAL_HITTEST_NOWHERE
:
1496 wxCalendarHitTestResult
wxCalendarCtrl::HitTest(const wxPoint
& pos
,
1498 wxDateTime::WeekDay
*wd
)
1504 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1505 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
1509 // we need to find out if the hit is on left arrow, on month or on right arrow
1511 if ( wxRegion(m_leftArrowRect
).Contains(pos
) == wxInRegion
)
1515 if ( IsDateInRange(m_date
- wxDateSpan::Month()) )
1517 *date
= m_date
- wxDateSpan::Month();
1521 *date
= GetLowerDateLimit();
1525 return wxCAL_HITTEST_DECMONTH
;
1528 if ( wxRegion(m_rightArrowRect
).Contains(pos
) == wxInRegion
)
1532 if ( IsDateInRange(m_date
+ wxDateSpan::Month()) )
1534 *date
= m_date
+ wxDateSpan::Month();
1538 *date
= GetUpperDateLimit();
1542 return wxCAL_HITTEST_INCMONTH
;
1547 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1549 int wday
= pos
.x
/ m_widthCol
;
1550 // if ( y < m_heightRow )
1551 if ( y
< (m_heightRow
+ m_rowOffset
) )
1553 if ( y
> m_rowOffset
)
1557 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST
)
1559 wday
= wday
== 6 ? 0 : wday
+ 1;
1562 *wd
= (wxDateTime::WeekDay
)wday
;
1565 return wxCAL_HITTEST_HEADER
;
1569 return wxCAL_HITTEST_NOWHERE
;
1573 // int week = (y - m_heightRow) / m_heightRow;
1574 int week
= (y
- (m_heightRow
+ m_rowOffset
)) / m_heightRow
;
1575 if ( week
>= 6 || wday
>= 7 )
1577 return wxCAL_HITTEST_NOWHERE
;
1580 wxDateTime dt
= GetStartDate() + wxDateSpan::Days(7*week
+ wday
);
1582 if ( IsDateShown(dt
) )
1587 if ( dt
.GetMonth() == m_date
.GetMonth() )
1590 return wxCAL_HITTEST_DAY
;
1594 return wxCAL_HITTEST_SURROUNDING_WEEK
;
1599 return wxCAL_HITTEST_NOWHERE
;
1603 // ----------------------------------------------------------------------------
1604 // subcontrols events handling
1605 // ----------------------------------------------------------------------------
1607 void wxCalendarCtrl::OnMonthChange(wxCommandEvent
& event
)
1609 wxDateTime::Tm tm
= m_date
.GetTm();
1611 wxDateTime::Month mon
= (wxDateTime::Month
)event
.GetInt();
1612 if ( tm
.mday
> wxDateTime::GetNumberOfDays(mon
, tm
.year
) )
1614 tm
.mday
= wxDateTime::GetNumberOfDays(mon
, tm
.year
);
1617 wxDateTime target
= wxDateTime(tm
.mday
, mon
, tm
.year
);
1619 ChangeMonth(&target
);
1620 SetDateAndNotify(target
);
1623 void wxCalendarCtrl::OnYearChange(wxCommandEvent
& event
)
1625 int year
= (int)event
.GetInt();
1626 if ( year
== INT_MIN
)
1628 // invalid year in the spin control, ignore it
1632 wxDateTime::Tm tm
= m_date
.GetTm();
1634 if ( tm
.mday
> wxDateTime::GetNumberOfDays(tm
.mon
, year
) )
1636 tm
.mday
= wxDateTime::GetNumberOfDays(tm
.mon
, year
);
1639 wxDateTime target
= wxDateTime(tm
.mday
, tm
.mon
, year
);
1641 if ( ChangeYear(&target
) )
1643 SetDateAndNotify(target
);
1647 // In this case we don't want to change the date. That would put us
1648 // inside the same year but a strange number of months forward/back..
1649 m_spinYear
->SetValue(target
.GetYear());
1653 // ----------------------------------------------------------------------------
1654 // keyboard interface
1655 // ----------------------------------------------------------------------------
1657 void wxCalendarCtrl::OnChar(wxKeyEvent
& event
)
1660 switch ( event
.GetKeyCode() )
1664 target
= m_date
+ wxDateSpan::Year();
1665 if ( ChangeYear(&target
) )
1667 SetDateAndNotify(target
);
1673 target
= m_date
- wxDateSpan::Year();
1674 if ( ChangeYear(&target
) )
1676 SetDateAndNotify(target
);
1681 target
= m_date
- wxDateSpan::Month();
1682 ChangeMonth(&target
);
1683 SetDateAndNotify(target
); // always
1687 target
= m_date
+ wxDateSpan::Month();
1688 ChangeMonth(&target
);
1689 SetDateAndNotify(target
); // always
1693 if ( event
.ControlDown() )
1695 target
= wxDateTime(m_date
).SetToNextWeekDay(
1696 GetWindowStyle() & wxCAL_MONDAY_FIRST
1697 ? wxDateTime::Sun
: wxDateTime::Sat
);
1698 if ( !IsDateInRange(target
) )
1700 target
= GetUpperDateLimit();
1702 SetDateAndNotify(target
);
1705 SetDateAndNotify(m_date
+ wxDateSpan::Day());
1709 if ( event
.ControlDown() )
1711 target
= wxDateTime(m_date
).SetToPrevWeekDay(
1712 GetWindowStyle() & wxCAL_MONDAY_FIRST
1713 ? wxDateTime::Mon
: wxDateTime::Sun
);
1714 if ( !IsDateInRange(target
) )
1716 target
= GetLowerDateLimit();
1718 SetDateAndNotify(target
);
1721 SetDateAndNotify(m_date
- wxDateSpan::Day());
1725 SetDateAndNotify(m_date
- wxDateSpan::Week());
1729 SetDateAndNotify(m_date
+ wxDateSpan::Week());
1733 if ( event
.ControlDown() )
1734 SetDateAndNotify(wxDateTime::Today());
1736 SetDateAndNotify(wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear()));
1740 SetDateAndNotify(wxDateTime(m_date
).SetToLastMonthDay());
1744 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1752 // ----------------------------------------------------------------------------
1753 // holidays handling
1754 // ----------------------------------------------------------------------------
1756 void wxCalendarCtrl::EnableHolidayDisplay(bool display
)
1758 long style
= GetWindowStyle();
1760 style
|= wxCAL_SHOW_HOLIDAYS
;
1762 style
&= ~wxCAL_SHOW_HOLIDAYS
;
1764 SetWindowStyle(style
);
1769 ResetHolidayAttrs();
1774 void wxCalendarCtrl::SetHolidayAttrs()
1776 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS
)
1778 ResetHolidayAttrs();
1780 wxDateTime::Tm tm
= m_date
.GetTm();
1781 wxDateTime
dtStart(1, tm
.mon
, tm
.year
),
1782 dtEnd
= dtStart
.GetLastMonthDay();
1784 wxDateTimeArray hol
;
1785 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart
, dtEnd
, hol
);
1787 size_t count
= hol
.GetCount();
1788 for ( size_t n
= 0; n
< count
; n
++ )
1790 SetHoliday(hol
[n
].GetDay());
1795 void wxCalendarCtrl::SetHoliday(size_t day
)
1797 wxCHECK_RET( day
> 0 && day
< 32, _T("invalid day in SetHoliday") );
1799 wxCalendarDateAttr
*attr
= GetAttr(day
);
1802 attr
= new wxCalendarDateAttr
;
1805 attr
->SetHoliday(TRUE
);
1807 // can't use SetAttr() because it would delete this pointer
1808 m_attrs
[day
- 1] = attr
;
1811 void wxCalendarCtrl::ResetHolidayAttrs()
1813 for ( size_t day
= 0; day
< 31; day
++ )
1817 m_attrs
[day
]->SetHoliday(FALSE
);
1822 // ----------------------------------------------------------------------------
1824 // ----------------------------------------------------------------------------
1826 void wxCalendarEvent::Init()
1828 m_wday
= wxDateTime::Inv_WeekDay
;
1831 wxCalendarEvent::wxCalendarEvent(wxCalendarCtrl
*cal
, wxEventType type
)
1832 : wxCommandEvent(type
, cal
->GetId())
1834 m_date
= cal
->GetDate();
1835 SetEventObject(cal
);
1838 #endif // wxUSE_CALENDARCTRL