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 #define _WX_DEFINE_DATE_EVENTS_
46 #include "wx/calctrl.h"
50 // ----------------------------------------------------------------------------
52 // ----------------------------------------------------------------------------
54 class wxMonthComboBox
: public wxComboBox
57 wxMonthComboBox(wxCalendarCtrl
*cal
);
59 void OnMonthChange(wxCommandEvent
& event
) { m_cal
->OnMonthChange(event
); }
62 wxCalendarCtrl
*m_cal
;
65 DECLARE_NO_COPY_CLASS(wxMonthComboBox
)
68 class wxYearSpinCtrl
: public wxSpinCtrl
71 wxYearSpinCtrl(wxCalendarCtrl
*cal
);
73 void OnYearTextChange(wxCommandEvent
& event
)
75 m_cal
->SetUserChangedYear();
76 m_cal
->OnYearChange(event
);
78 void OnYearChange(wxSpinEvent
& event
) { m_cal
->OnYearChange(event
); }
81 wxCalendarCtrl
*m_cal
;
84 DECLARE_NO_COPY_CLASS(wxYearSpinCtrl
)
87 // ----------------------------------------------------------------------------
89 // ----------------------------------------------------------------------------
91 BEGIN_EVENT_TABLE(wxCalendarCtrl
, wxControl
)
92 EVT_PAINT(wxCalendarCtrl::OnPaint
)
94 EVT_CHAR(wxCalendarCtrl::OnChar
)
96 EVT_LEFT_DOWN(wxCalendarCtrl::OnClick
)
97 EVT_LEFT_DCLICK(wxCalendarCtrl::OnDClick
)
100 BEGIN_EVENT_TABLE(wxMonthComboBox
, wxComboBox
)
101 EVT_COMBOBOX(wxID_ANY
, wxMonthComboBox::OnMonthChange
)
104 BEGIN_EVENT_TABLE(wxYearSpinCtrl
, wxSpinCtrl
)
105 EVT_TEXT(wxID_ANY
, wxYearSpinCtrl::OnYearTextChange
)
106 EVT_SPINCTRL(wxID_ANY
, wxYearSpinCtrl::OnYearChange
)
109 #if wxUSE_EXTENDED_RTTI
110 WX_DEFINE_FLAGS( wxCalendarCtrlStyle
)
112 wxBEGIN_FLAGS( wxCalendarCtrlStyle
)
113 // new style border flags, we put them first to
114 // use them for streaming out
115 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
116 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
117 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
118 wxFLAGS_MEMBER(wxBORDER_RAISED
)
119 wxFLAGS_MEMBER(wxBORDER_STATIC
)
120 wxFLAGS_MEMBER(wxBORDER_NONE
)
122 // old style border flags
123 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
124 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
125 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
126 wxFLAGS_MEMBER(wxRAISED_BORDER
)
127 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
128 wxFLAGS_MEMBER(wxBORDER
)
130 // standard window styles
131 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
132 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
133 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
134 wxFLAGS_MEMBER(wxWANTS_CHARS
)
135 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
136 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
137 wxFLAGS_MEMBER(wxVSCROLL
)
138 wxFLAGS_MEMBER(wxHSCROLL
)
140 wxFLAGS_MEMBER(wxCAL_SUNDAY_FIRST
)
141 wxFLAGS_MEMBER(wxCAL_MONDAY_FIRST
)
142 wxFLAGS_MEMBER(wxCAL_SHOW_HOLIDAYS
)
143 wxFLAGS_MEMBER(wxCAL_NO_YEAR_CHANGE
)
144 wxFLAGS_MEMBER(wxCAL_NO_MONTH_CHANGE
)
145 wxFLAGS_MEMBER(wxCAL_SEQUENTIAL_MONTH_SELECTION
)
146 wxFLAGS_MEMBER(wxCAL_SHOW_SURROUNDING_WEEKS
)
148 wxEND_FLAGS( wxCalendarCtrlStyle
)
150 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCalendarCtrl
, wxControl
,"wx/calctrl.h")
152 wxBEGIN_PROPERTIES_TABLE(wxCalendarCtrl
)
153 wxEVENT_RANGE_PROPERTY( Updated
, wxEVT_CALENDAR_SEL_CHANGED
, wxEVT_CALENDAR_WEEKDAY_CLICKED
, wxCalendarEvent
)
154 wxHIDE_PROPERTY( Children
)
155 wxPROPERTY( Date
,wxDateTime
, SetDate
, GetDate
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
156 wxPROPERTY_FLAGS( WindowStyle
, wxCalendarCtrlStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
157 wxEND_PROPERTIES_TABLE()
159 wxBEGIN_HANDLERS_TABLE(wxCalendarCtrl
)
160 wxEND_HANDLERS_TABLE()
162 wxCONSTRUCTOR_6( wxCalendarCtrl
, wxWindow
* , Parent
, wxWindowID
, Id
, wxDateTime
, Date
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
164 IMPLEMENT_DYNAMIC_CLASS(wxCalendarCtrl
, wxControl
)
166 IMPLEMENT_DYNAMIC_CLASS(wxCalendarEvent
, wxDateEvent
)
168 // ----------------------------------------------------------------------------
170 // ----------------------------------------------------------------------------
172 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_SEL_CHANGED
)
173 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DAY_CHANGED
)
174 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_MONTH_CHANGED
)
175 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_YEAR_CHANGED
)
176 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DOUBLECLICKED
)
177 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_WEEKDAY_CLICKED
)
179 // ============================================================================
181 // ============================================================================
183 // ----------------------------------------------------------------------------
184 // wxMonthComboBox and wxYearSpinCtrl
185 // ----------------------------------------------------------------------------
187 wxMonthComboBox::wxMonthComboBox(wxCalendarCtrl
*cal
)
188 : wxComboBox(cal
->GetParent(), wxID_ANY
,
193 wxCB_READONLY
| wxCLIP_SIBLINGS
)
198 for ( m
= wxDateTime::Jan
; m
< wxDateTime::Inv_Month
; wxNextMonth(m
) )
200 Append(wxDateTime::GetMonthName(m
));
203 SetSelection(m_cal
->GetDate().GetMonth());
204 SetSize(wxDefaultCoord
,
208 wxSIZE_AUTO_WIDTH
|wxSIZE_AUTO_HEIGHT
);
211 wxYearSpinCtrl::wxYearSpinCtrl(wxCalendarCtrl
*cal
)
212 : wxSpinCtrl(cal
->GetParent(), wxID_ANY
,
213 cal
->GetDate().Format(_T("%Y")),
216 wxSP_ARROW_KEYS
| wxCLIP_SIBLINGS
,
217 -4300, 10000, cal
->GetDate().GetYear())
223 // ----------------------------------------------------------------------------
225 // ----------------------------------------------------------------------------
227 wxCalendarCtrl::wxCalendarCtrl(wxWindow
*parent
,
229 const wxDateTime
& date
,
233 const wxString
& name
)
237 (void)Create(parent
, id
, date
, pos
, size
, style
, name
);
240 void wxCalendarCtrl::Init()
245 m_staticMonth
= NULL
;
247 m_userChangedYear
= false;
252 wxDateTime::WeekDay wd
;
253 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
255 m_weekdays
[wd
] = wxDateTime::GetWeekDayName(wd
, wxDateTime::Name_Abbr
);
258 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
263 m_colHighlightFg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
264 m_colHighlightBg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
);
266 m_colHolidayFg
= *wxRED
;
267 // don't set m_colHolidayBg - by default, same as our bg colour
269 m_colHeaderFg
= *wxBLUE
;
270 m_colHeaderBg
= *wxLIGHT_GREY
;
273 bool wxCalendarCtrl::Create(wxWindow
*parent
,
275 const wxDateTime
& date
,
279 const wxString
& name
)
281 if ( !wxControl::Create(parent
, id
, pos
, size
,
282 style
| wxCLIP_CHILDREN
| wxWANTS_CHARS
,
283 wxDefaultValidator
, name
) )
288 // needed to get the arrow keys normally used for the dialog navigation
289 SetWindowStyle(style
| wxWANTS_CHARS
);
291 m_date
= date
.IsValid() ? date
: wxDateTime::Today();
293 m_lowdate
= wxDefaultDateTime
;
294 m_highdate
= wxDefaultDateTime
;
296 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
298 m_spinYear
= new wxYearSpinCtrl(this);
299 m_staticYear
= new wxStaticText(GetParent(), wxID_ANY
, m_date
.Format(_T("%Y")),
300 wxDefaultPosition
, wxDefaultSize
,
303 m_comboMonth
= new wxMonthComboBox(this);
304 m_staticMonth
= new wxStaticText(GetParent(), wxID_ANY
, m_date
.Format(_T("%B")),
305 wxDefaultPosition
, wxDefaultSize
,
309 ShowCurrentControls();
311 // we need to set the position as well because the main control position
312 // is not the same as the one specified in pos if we have the controls
317 // Since we don't paint the whole background make sure that the platform
318 // will use the right one.
319 SetBackgroundColour(GetBackgroundColour());
326 wxCalendarCtrl::~wxCalendarCtrl()
328 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
334 // ----------------------------------------------------------------------------
335 // forward wxWin functions to subcontrols
336 // ----------------------------------------------------------------------------
338 bool wxCalendarCtrl::Destroy()
341 m_staticYear
->Destroy();
343 m_spinYear
->Destroy();
345 m_comboMonth
->Destroy();
347 m_staticMonth
->Destroy();
352 m_staticMonth
= NULL
;
354 return wxControl::Destroy();
357 bool wxCalendarCtrl::Show(bool show
)
359 if ( !wxControl::Show(show
) )
364 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
366 if ( GetMonthControl() )
368 GetMonthControl()->Show(show
);
369 GetYearControl()->Show(show
);
376 bool wxCalendarCtrl::Enable(bool enable
)
378 if ( !wxControl::Enable(enable
) )
383 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
385 GetMonthControl()->Enable(enable
);
386 GetYearControl()->Enable(enable
);
392 // ----------------------------------------------------------------------------
393 // enable/disable month/year controls
394 // ----------------------------------------------------------------------------
396 void wxCalendarCtrl::ShowCurrentControls()
398 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
400 if ( AllowMonthChange() )
402 m_comboMonth
->Show();
403 m_staticMonth
->Hide();
405 if ( AllowYearChange() )
408 m_staticYear
->Hide();
416 m_comboMonth
->Hide();
417 m_staticMonth
->Show();
420 // year change not allowed here
422 m_staticYear
->Show();
426 wxControl
*wxCalendarCtrl::GetMonthControl() const
428 return AllowMonthChange() ? (wxControl
*)m_comboMonth
: (wxControl
*)m_staticMonth
;
431 wxControl
*wxCalendarCtrl::GetYearControl() const
433 return AllowYearChange() ? (wxControl
*)m_spinYear
: (wxControl
*)m_staticYear
;
436 void wxCalendarCtrl::EnableYearChange(bool enable
)
438 if ( enable
!= AllowYearChange() )
440 long style
= GetWindowStyle();
442 style
&= ~wxCAL_NO_YEAR_CHANGE
;
444 style
|= wxCAL_NO_YEAR_CHANGE
;
445 SetWindowStyle(style
);
447 ShowCurrentControls();
448 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
455 void wxCalendarCtrl::EnableMonthChange(bool enable
)
457 if ( enable
!= AllowMonthChange() )
459 long style
= GetWindowStyle();
461 style
&= ~wxCAL_NO_MONTH_CHANGE
;
463 style
|= wxCAL_NO_MONTH_CHANGE
;
464 SetWindowStyle(style
);
466 ShowCurrentControls();
467 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
474 // ----------------------------------------------------------------------------
476 // ----------------------------------------------------------------------------
478 bool wxCalendarCtrl::SetDate(const wxDateTime
& date
)
482 bool sameMonth
= m_date
.GetMonth() == date
.GetMonth(),
483 sameYear
= m_date
.GetYear() == date
.GetYear();
485 if ( IsDateInRange(date
) )
487 if ( sameMonth
&& sameYear
)
489 // just change the day
494 if ( AllowMonthChange() && (AllowYearChange() || sameYear
) )
499 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
501 // update the controls
502 m_comboMonth
->SetSelection(m_date
.GetMonth());
504 if ( AllowYearChange() )
506 if ( !m_userChangedYear
)
507 m_spinYear
->SetValue(m_date
.Format(_T("%Y")));
511 // as the month changed, holidays did too
514 // update the calendar
525 m_userChangedYear
= false;
530 void wxCalendarCtrl::ChangeDay(const wxDateTime
& date
)
532 if ( m_date
!= date
)
534 // we need to refresh the row containing the old date and the one
535 // containing the new one
536 wxDateTime dateOld
= m_date
;
539 RefreshDate(dateOld
);
541 // if the date is in the same row, it was already drawn correctly
542 if ( GetWeek(m_date
) != GetWeek(dateOld
) )
549 void wxCalendarCtrl::SetDateAndNotify(const wxDateTime
& date
)
551 wxDateTime::Tm tm1
= m_date
.GetTm(),
555 if ( tm1
.year
!= tm2
.year
)
556 type
= wxEVT_CALENDAR_YEAR_CHANGED
;
557 else if ( tm1
.mon
!= tm2
.mon
)
558 type
= wxEVT_CALENDAR_MONTH_CHANGED
;
559 else if ( tm1
.mday
!= tm2
.mday
)
560 type
= wxEVT_CALENDAR_DAY_CHANGED
;
566 GenerateEvents(type
, wxEVT_CALENDAR_SEL_CHANGED
);
570 // ----------------------------------------------------------------------------
572 // ----------------------------------------------------------------------------
574 bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
578 if ( !(date
.IsValid()) || ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) )
590 bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
594 if ( !(date
.IsValid()) || ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true ) )
606 bool wxCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
/* = wxDefaultDateTime */, const wxDateTime
& upperdate
/* = wxDefaultDateTime */)
611 ( !( lowerdate
.IsValid() ) || ( ( upperdate
.IsValid() ) ? ( lowerdate
<= upperdate
) : true ) ) &&
612 ( !( upperdate
.IsValid() ) || ( ( lowerdate
.IsValid() ) ? ( upperdate
>= lowerdate
) : true ) ) )
614 m_lowdate
= lowerdate
;
615 m_highdate
= upperdate
;
625 // ----------------------------------------------------------------------------
627 // ----------------------------------------------------------------------------
629 wxDateTime
wxCalendarCtrl::GetStartDate() const
631 wxDateTime::Tm tm
= m_date
.GetTm();
633 wxDateTime date
= wxDateTime(1, tm
.mon
, tm
.year
);
636 date
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
637 ? wxDateTime::Mon
: wxDateTime::Sun
);
639 if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
)
641 // We want to offset the calendar if we start on the first..
642 if ( date
.GetDay() == 1 )
644 date
-= wxDateSpan::Week();
651 bool wxCalendarCtrl::IsDateShown(const wxDateTime
& date
) const
653 if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
655 return date
.GetMonth() == m_date
.GetMonth();
663 bool wxCalendarCtrl::IsDateInRange(const wxDateTime
& date
) const
665 // Check if the given date is in the range specified
666 return ( ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true )
667 && ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) );
670 bool wxCalendarCtrl::ChangeYear(wxDateTime
* target
) const
674 if ( !(IsDateInRange(*target
)) )
676 if ( target
->GetYear() < m_date
.GetYear() )
678 if ( target
->GetYear() >= GetLowerDateLimit().GetYear() )
680 *target
= GetLowerDateLimit();
690 if ( target
->GetYear() <= GetUpperDateLimit().GetYear() )
692 *target
= GetUpperDateLimit();
709 bool wxCalendarCtrl::ChangeMonth(wxDateTime
* target
) const
713 if ( !(IsDateInRange(*target
)) )
717 if ( target
->GetMonth() < m_date
.GetMonth() )
719 *target
= GetLowerDateLimit();
723 *target
= GetUpperDateLimit();
730 size_t wxCalendarCtrl::GetWeek(const wxDateTime
& date
) const
732 size_t retval
= date
.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
733 ? wxDateTime::Monday_First
734 : wxDateTime::Sunday_First
);
736 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
738 // we need to offset an extra week if we "start" on the 1st of the month
739 wxDateTime::Tm tm
= date
.GetTm();
741 wxDateTime datetest
= wxDateTime(1, tm
.mon
, tm
.year
);
744 datetest
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
745 ? wxDateTime::Mon
: wxDateTime::Sun
);
747 if ( datetest
.GetDay() == 1 )
756 // ----------------------------------------------------------------------------
758 // ----------------------------------------------------------------------------
760 // this is a composite control and it must arrange its parts each time its
761 // size or position changes: the combobox and spinctrl are along the top of
762 // the available area and the calendar takes up therest of the space
764 // the static controls are supposed to be always smaller than combo/spin so we
765 // always use the latter for size calculations and position the static to take
768 // the constants used for the layout
769 #define VERT_MARGIN 5 // distance between combo and calendar
771 #define HORZ_MARGIN 5 // spin
773 #define HORZ_MARGIN 15 // spin
775 wxSize
wxCalendarCtrl::DoGetBestSize() const
777 // calc the size of the calendar
778 ((wxCalendarCtrl
*)this)->RecalcGeometry(); // const_cast
780 wxCoord width
= 7*m_widthCol
,
781 height
= 7*m_heightRow
+ m_rowOffset
+ VERT_MARGIN
;
783 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
785 // the combobox doesn't report its height correctly (it returns the
786 // height including the drop down list) so don't use it
787 height
+= m_spinYear
->GetBestSize().y
;
790 if ( !HasFlag(wxBORDER_NONE
) )
792 // the border would clip the last line otherwise
797 wxSize
best(width
, height
);
802 void wxCalendarCtrl::DoSetSize(int x
, int y
,
803 int width
, int height
,
806 wxControl::DoSetSize(x
, y
, width
, height
, sizeFlags
);
809 void wxCalendarCtrl::DoMoveWindow(int x
, int y
, int width
, int height
)
813 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
815 wxSize sizeCombo
= m_comboMonth
->GetSize();
816 wxSize sizeStatic
= m_staticMonth
->GetSize();
817 wxSize sizeSpin
= m_spinYear
->GetSize();
818 int dy
= (sizeCombo
.y
- sizeStatic
.y
) / 2;
820 In the calender the size of the combobox for the year
821 is just defined by a margin from the month combobox to
822 the left border. While in wxUniv the year control can't
823 show all 4 digits, in wxMsw it show almost twice as
824 much. Instead the year should use it's best size and be
825 left aligned to the calendar. Just in case the month in
826 any language is longer than it has space in the
827 calendar it is shortend.This way the year always can
830 This patch relies on the fact that a combobox has a
831 good best size implementation. This is not the case
832 with wxMSW but I don't know why.
837 #ifdef __WXUNIVERSAL__
838 if (sizeCombo
.x
+ HORZ_MARGIN
- sizeSpin
.x
> width
)
840 m_comboMonth
->SetSize(x
, y
, width
- HORZ_MARGIN
- sizeSpin
.x
, sizeCombo
.y
);
844 m_comboMonth
->Move(x
, y
);
846 m_staticMonth
->Move(x
, y
+ dy
);
847 m_spinYear
->Move(x
+ width
- sizeSpin
.x
, y
);
848 m_staticYear
->Move(x
+ width
- sizeSpin
.x
, y
+ dy
);
850 m_comboMonth
->Move(x
, y
);
851 m_staticMonth
->SetSize(x
, y
+ dy
, sizeCombo
.x
, sizeStatic
.y
);
853 int xDiff
= sizeCombo
.x
+ HORZ_MARGIN
;
855 m_spinYear
->SetSize(x
+ xDiff
, y
, width
- xDiff
, sizeCombo
.y
);
856 m_staticYear
->SetSize(x
+ xDiff
, y
+ dy
, width
- xDiff
, sizeStatic
.y
);
858 yDiff
= wxMax(sizeSpin
.y
, sizeCombo
.y
) + VERT_MARGIN
;
860 else // no controls on the top
865 wxControl::DoMoveWindow(x
, y
+ yDiff
, width
, height
- yDiff
);
868 void wxCalendarCtrl::DoGetPosition(int *x
, int *y
) const
870 wxControl::DoGetPosition(x
, y
);
872 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
874 // our real top corner is not in this position
877 *y
-= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
882 void wxCalendarCtrl::DoGetSize(int *width
, int *height
) const
884 wxControl::DoGetSize(width
, height
);
886 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
888 // our real height is bigger
889 if ( height
&& GetMonthControl())
891 *height
+= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
896 void wxCalendarCtrl::RecalcGeometry()
900 dc
.SetFont(GetFont());
902 // determine the column width (we assume that the weekday names are always
903 // wider (in any language) than the numbers)
905 wxDateTime::WeekDay wd
;
906 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
909 dc
.GetTextExtent(m_weekdays
[wd
], &width
, &m_heightRow
);
910 if ( width
> m_widthCol
)
916 // leave some margins
920 m_rowOffset
= (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) ? m_heightRow
: 0; // conditional in relation to style
923 // ----------------------------------------------------------------------------
925 // ----------------------------------------------------------------------------
927 void wxCalendarCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
))
931 dc
.SetFont(GetFont());
936 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
937 m_date
.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
943 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
945 // draw the sequential month-selector
947 dc
.SetBackgroundMode(wxTRANSPARENT
);
948 dc
.SetTextForeground(*wxBLACK
);
949 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
950 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
951 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
953 // Get extent of month-name + year
954 wxCoord monthw
, monthh
;
955 wxString headertext
= m_date
.Format(wxT("%B %Y"));
956 dc
.GetTextExtent(headertext
, &monthw
, &monthh
);
958 // draw month-name centered above weekdays
959 wxCoord monthx
= ((m_widthCol
* 7) - monthw
) / 2;
960 wxCoord monthy
= ((m_heightRow
- monthh
) / 2) + y
;
961 dc
.DrawText(headertext
, monthx
, monthy
);
963 // calculate the "month-arrows"
964 wxPoint leftarrow
[3];
965 wxPoint rightarrow
[3];
967 int arrowheight
= monthh
/ 2;
969 leftarrow
[0] = wxPoint(0, arrowheight
/ 2);
970 leftarrow
[1] = wxPoint(arrowheight
/ 2, 0);
971 leftarrow
[2] = wxPoint(arrowheight
/ 2, arrowheight
- 1);
973 rightarrow
[0] = wxPoint(0, 0);
974 rightarrow
[1] = wxPoint(arrowheight
/ 2, arrowheight
/ 2);
975 rightarrow
[2] = wxPoint(0, arrowheight
- 1);
977 // draw the "month-arrows"
979 wxCoord arrowy
= (m_heightRow
- arrowheight
) / 2;
980 wxCoord larrowx
= (m_widthCol
- (arrowheight
/ 2)) / 2;
981 wxCoord rarrowx
= ((m_widthCol
- (arrowheight
/ 2)) / 2) + m_widthCol
*6;
982 m_leftArrowRect
= wxRect(0, 0, 0, 0);
983 m_rightArrowRect
= wxRect(0, 0, 0, 0);
985 if ( AllowMonthChange() )
987 wxDateTime ldpm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) - wxDateSpan::Day(); // last day prev month
988 // Check if range permits change
989 if ( IsDateInRange(ldpm
) && ( ( ldpm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
991 m_leftArrowRect
= wxRect(larrowx
- 3, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
992 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
993 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
994 dc
.DrawPolygon(3, leftarrow
, larrowx
, arrowy
, wxWINDING_RULE
);
995 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
996 dc
.DrawRectangle(m_leftArrowRect
);
998 wxDateTime fdnm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) + wxDateSpan::Month(); // first day next month
999 if ( IsDateInRange(fdnm
) && ( ( fdnm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
1001 m_rightArrowRect
= wxRect(rarrowx
- 4, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1002 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1003 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1004 dc
.DrawPolygon(3, rightarrow
, rarrowx
, arrowy
, wxWINDING_RULE
);
1005 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1006 dc
.DrawRectangle(m_rightArrowRect
);
1013 // first draw the week days
1014 if ( IsExposed(0, y
, 7*m_widthCol
, m_heightRow
) )
1017 wxLogDebug("painting the header");
1020 dc
.SetBackgroundMode(wxTRANSPARENT
);
1021 dc
.SetTextForeground(m_colHeaderFg
);
1022 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
1023 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
1024 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
1026 bool startOnMonday
= (GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1027 for ( size_t wd
= 0; wd
< 7; wd
++ )
1030 if ( startOnMonday
)
1031 n
= wd
== 6 ? 0 : wd
+ 1;
1035 dc
.GetTextExtent(m_weekdays
[n
], &dayw
, &dayh
);
1036 dc
.DrawText(m_weekdays
[n
], (wd
*m_widthCol
) + ((m_widthCol
- dayw
) / 2), y
); // center the day-name
1040 // then the calendar itself
1041 dc
.SetTextForeground(*wxBLACK
);
1042 //dc.SetFont(*wxNORMAL_FONT);
1045 wxDateTime date
= GetStartDate();
1048 wxLogDebug("starting calendar from %s\n",
1049 date
.Format("%a %d-%m-%Y %H:%M:%S").c_str());
1052 dc
.SetBackgroundMode(wxSOLID
);
1053 for ( size_t nWeek
= 1; nWeek
<= 6; nWeek
++, y
+= m_heightRow
)
1055 // if the update region doesn't intersect this row, don't paint it
1056 if ( !IsExposed(0, y
, 7*m_widthCol
, m_heightRow
- 1) )
1058 date
+= wxDateSpan::Week();
1064 wxLogDebug("painting week %d at y = %d\n", nWeek
, y
);
1067 for ( size_t wd
= 0; wd
< 7; wd
++ )
1069 if ( IsDateShown(date
) )
1071 // don't use wxDate::Format() which prepends 0s
1072 unsigned int day
= date
.GetDay();
1073 wxString dayStr
= wxString::Format(_T("%u"), day
);
1075 dc
.GetTextExtent(dayStr
, &width
, (wxCoord
*)NULL
);
1077 bool changedColours
= false,
1078 changedFont
= false;
1081 wxCalendarDateAttr
*attr
= NULL
;
1083 if ( date
.GetMonth() != m_date
.GetMonth() || !IsDateInRange(date
) )
1085 // surrounding week or out-of-range
1087 dc
.SetTextForeground(*wxLIGHT_GREY
);
1088 changedColours
= true;
1092 isSel
= date
.IsSameDate(m_date
);
1093 attr
= m_attrs
[day
- 1];
1097 dc
.SetTextForeground(m_colHighlightFg
);
1098 dc
.SetTextBackground(m_colHighlightBg
);
1100 changedColours
= true;
1104 wxColour colFg
, colBg
;
1106 if ( attr
->IsHoliday() )
1108 colFg
= m_colHolidayFg
;
1109 colBg
= m_colHolidayBg
;
1113 colFg
= attr
->GetTextColour();
1114 colBg
= attr
->GetBackgroundColour();
1119 dc
.SetTextForeground(colFg
);
1120 changedColours
= true;
1125 dc
.SetTextBackground(colBg
);
1126 changedColours
= true;
1129 if ( attr
->HasFont() )
1131 dc
.SetFont(attr
->GetFont());
1137 wxCoord x
= wd
*m_widthCol
+ (m_widthCol
- width
) / 2;
1138 dc
.DrawText(dayStr
, x
, y
+ 1);
1140 if ( !isSel
&& attr
&& attr
->HasBorder() )
1143 if ( attr
->HasBorderColour() )
1145 colBorder
= attr
->GetBorderColour();
1149 colBorder
= GetForegroundColour();
1152 wxPen
pen(colBorder
, 1, wxSOLID
);
1154 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1156 switch ( attr
->GetBorder() )
1158 case wxCAL_BORDER_SQUARE
:
1159 dc
.DrawRectangle(x
- 2, y
,
1160 width
+ 4, m_heightRow
);
1163 case wxCAL_BORDER_ROUND
:
1164 dc
.DrawEllipse(x
- 2, y
,
1165 width
+ 4, m_heightRow
);
1169 wxFAIL_MSG(_T("unknown border type"));
1173 if ( changedColours
)
1175 dc
.SetTextForeground(GetForegroundColour());
1176 dc
.SetTextBackground(GetBackgroundColour());
1181 dc
.SetFont(GetFont());
1184 //else: just don't draw it
1186 date
+= wxDateSpan::Day();
1190 // Greying out out-of-range background
1191 bool showSurrounding
= (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) != 0;
1193 date
= ( showSurrounding
) ? GetStartDate() : wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear());
1194 if ( !IsDateInRange(date
) )
1196 wxDateTime firstOOR
= GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1198 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1199 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1201 HighlightRange(&dc
, date
, firstOOR
, wxTRANSPARENT_PEN
, &oorbrush
);
1204 date
= ( showSurrounding
) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear());
1205 if ( !IsDateInRange(date
) )
1207 wxDateTime firstOOR
= GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1209 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1210 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1212 HighlightRange(&dc
, firstOOR
, date
, wxTRANSPARENT_PEN
, &oorbrush
);
1216 wxLogDebug("+++ finished painting");
1220 void wxCalendarCtrl::RefreshDate(const wxDateTime
& date
)
1226 // always refresh the whole row at once because our OnPaint() will draw
1227 // the whole row anyhow - and this allows the small optimisation in
1228 // OnClick() below to work
1231 rect
.y
= (m_heightRow
* GetWeek(date
)) + m_rowOffset
;
1233 rect
.width
= 7*m_widthCol
;
1234 rect
.height
= m_heightRow
;
1237 // VZ: for some reason, the selected date seems to occupy more space under
1238 // MSW - this is probably some bug in the font size calculations, but I
1239 // don't know where exactly. This fix is ugly and leads to more
1240 // refreshes than really needed, but without it the selected days
1241 // leaves even more ugly underscores on screen.
1246 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
1249 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
1252 Refresh(true, &rect
);
1255 void wxCalendarCtrl::HighlightRange(wxPaintDC
* pDC
, const wxDateTime
& fromdate
, const wxDateTime
& todate
, wxPen
* pPen
, wxBrush
* pBrush
)
1257 // Highlights the given range using pen and brush
1258 // Does nothing if todate < fromdate
1262 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate
.Format("%d %m %Y"), todate
.Format("%d %m %Y"));
1265 if ( todate
>= fromdate
)
1272 // implicit: both dates must be currently shown - checked by GetDateCoord
1273 if ( GetDateCoord(fromdate
, &fd
, &fw
) && GetDateCoord(todate
, &td
, &tw
) )
1276 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd
, fw
, td
, tw
);
1278 if ( ( (tw
- fw
) == 1 ) && ( td
< fd
) )
1280 // special case: interval 7 days or less not in same week
1281 // split in two seperate intervals
1282 wxDateTime tfd
= fromdate
+ wxDateSpan::Days(7-fd
);
1283 wxDateTime ftd
= tfd
+ wxDateSpan::Day();
1285 wxLogDebug("Highlight: Seperate segments");
1288 HighlightRange(pDC
, fromdate
, tfd
, pPen
, pBrush
);
1289 HighlightRange(pDC
, ftd
, todate
, pPen
, pBrush
);
1294 wxPoint corners
[8]; // potentially 8 corners in polygon
1298 // simple case: same week
1300 corners
[0] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
);
1301 corners
[1] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1 ) * m_heightRow
) + m_rowOffset
);
1302 corners
[2] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
);
1303 corners
[3] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
);
1308 // "complex" polygon
1309 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1313 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1314 corners
[cidx
] = wxPoint(0, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1317 corners
[cidx
] = wxPoint(0, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1318 corners
[cidx
] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1322 corners
[cidx
] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1323 corners
[cidx
] = wxPoint(7 * m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1326 corners
[cidx
] = wxPoint(7 * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1332 pDC
->SetBrush(*pBrush
);
1334 pDC
->DrawPolygon(numpoints
, corners
);
1340 wxLogDebug("--- HighlightRange ---");
1344 bool wxCalendarCtrl::GetDateCoord(const wxDateTime
& date
, int *day
, int *week
) const
1349 wxLogDebug("+++ GetDateCoord: (%s) +++", date
.Format("%d %m %Y"));
1352 if ( IsDateShown(date
) )
1354 bool startOnMonday
= ( GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1357 *day
= date
.GetWeekDay();
1359 if ( *day
== 0 ) // sunday
1361 *day
= ( startOnMonday
) ? 7 : 1;
1365 *day
+= ( startOnMonday
) ? 0 : 1;
1368 int targetmonth
= date
.GetMonth() + (12 * date
.GetYear());
1369 int thismonth
= m_date
.GetMonth() + (12 * m_date
.GetYear());
1372 if ( targetmonth
== thismonth
)
1374 *week
= GetWeek(date
);
1378 if ( targetmonth
< thismonth
)
1380 *week
= 1; // trivial
1382 else // targetmonth > thismonth
1388 // get the datecoord of the last day in the month currently shown
1390 wxLogDebug(" +++ LDOM +++");
1392 GetDateCoord(ldcm
.SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear()), &lastday
, &lastweek
);
1394 wxLogDebug(" --- LDOM ---");
1397 wxTimeSpan span
= date
- ldcm
;
1399 int daysfromlast
= span
.GetDays();
1401 wxLogDebug("daysfromlast: %i", daysfromlast
);
1403 if ( daysfromlast
+ lastday
> 7 ) // past week boundary
1405 int wholeweeks
= (daysfromlast
/ 7);
1406 *week
= wholeweeks
+ lastweek
;
1407 if ( (daysfromlast
- (7 * wholeweeks
) + lastday
) > 7 )
1427 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date
.Format("%d %m %Y"), *day
, *week
);
1433 // ----------------------------------------------------------------------------
1435 // ----------------------------------------------------------------------------
1437 void wxCalendarCtrl::OnDClick(wxMouseEvent
& event
)
1439 if ( HitTest(event
.GetPosition()) != wxCAL_HITTEST_DAY
)
1445 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1449 void wxCalendarCtrl::OnClick(wxMouseEvent
& event
)
1452 wxDateTime::WeekDay wday
;
1453 switch ( HitTest(event
.GetPosition(), &date
, &wday
) )
1455 case wxCAL_HITTEST_DAY
:
1456 if ( IsDateInRange(date
) )
1460 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED
,
1461 wxEVT_CALENDAR_SEL_CHANGED
);
1465 case wxCAL_HITTEST_HEADER
:
1467 wxCalendarEvent
event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED
);
1468 event
.m_wday
= wday
;
1469 (void)GetEventHandler()->ProcessEvent(event
);
1473 case wxCAL_HITTEST_DECMONTH
:
1474 case wxCAL_HITTEST_INCMONTH
:
1475 case wxCAL_HITTEST_SURROUNDING_WEEK
:
1476 SetDateAndNotify(date
); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1480 wxFAIL_MSG(_T("unknown hittest code"));
1483 case wxCAL_HITTEST_NOWHERE
:
1489 wxCalendarHitTestResult
wxCalendarCtrl::HitTest(const wxPoint
& pos
,
1491 wxDateTime::WeekDay
*wd
)
1497 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1498 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
1502 // we need to find out if the hit is on left arrow, on month or on right arrow
1504 if ( wxRegion(m_leftArrowRect
).Contains(pos
) == wxInRegion
)
1508 if ( IsDateInRange(m_date
- wxDateSpan::Month()) )
1510 *date
= m_date
- wxDateSpan::Month();
1514 *date
= GetLowerDateLimit();
1518 return wxCAL_HITTEST_DECMONTH
;
1521 if ( wxRegion(m_rightArrowRect
).Contains(pos
) == wxInRegion
)
1525 if ( IsDateInRange(m_date
+ wxDateSpan::Month()) )
1527 *date
= m_date
+ wxDateSpan::Month();
1531 *date
= GetUpperDateLimit();
1535 return wxCAL_HITTEST_INCMONTH
;
1540 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1542 int wday
= pos
.x
/ m_widthCol
;
1543 // if ( y < m_heightRow )
1544 if ( y
< (m_heightRow
+ m_rowOffset
) )
1546 if ( y
> m_rowOffset
)
1550 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST
)
1552 wday
= wday
== 6 ? 0 : wday
+ 1;
1555 *wd
= (wxDateTime::WeekDay
)wday
;
1558 return wxCAL_HITTEST_HEADER
;
1562 return wxCAL_HITTEST_NOWHERE
;
1566 // int week = (y - m_heightRow) / m_heightRow;
1567 int week
= (y
- (m_heightRow
+ m_rowOffset
)) / m_heightRow
;
1568 if ( week
>= 6 || wday
>= 7 )
1570 return wxCAL_HITTEST_NOWHERE
;
1573 wxDateTime dt
= GetStartDate() + wxDateSpan::Days(7*week
+ wday
);
1575 if ( IsDateShown(dt
) )
1580 if ( dt
.GetMonth() == m_date
.GetMonth() )
1583 return wxCAL_HITTEST_DAY
;
1587 return wxCAL_HITTEST_SURROUNDING_WEEK
;
1592 return wxCAL_HITTEST_NOWHERE
;
1596 // ----------------------------------------------------------------------------
1597 // subcontrols events handling
1598 // ----------------------------------------------------------------------------
1600 void wxCalendarCtrl::OnMonthChange(wxCommandEvent
& event
)
1602 wxDateTime::Tm tm
= m_date
.GetTm();
1604 wxDateTime::Month mon
= (wxDateTime::Month
)event
.GetInt();
1605 if ( tm
.mday
> wxDateTime::GetNumberOfDays(mon
, tm
.year
) )
1607 tm
.mday
= wxDateTime::GetNumberOfDays(mon
, tm
.year
);
1610 wxDateTime target
= wxDateTime(tm
.mday
, mon
, tm
.year
);
1612 ChangeMonth(&target
);
1613 SetDateAndNotify(target
);
1616 void wxCalendarCtrl::OnYearChange(wxCommandEvent
& event
)
1618 int year
= (int)event
.GetInt();
1619 if ( year
== INT_MIN
)
1621 // invalid year in the spin control, ignore it
1625 wxDateTime::Tm tm
= m_date
.GetTm();
1627 if ( tm
.mday
> wxDateTime::GetNumberOfDays(tm
.mon
, year
) )
1629 tm
.mday
= wxDateTime::GetNumberOfDays(tm
.mon
, year
);
1632 wxDateTime target
= wxDateTime(tm
.mday
, tm
.mon
, year
);
1634 if ( ChangeYear(&target
) )
1636 SetDateAndNotify(target
);
1640 // In this case we don't want to change the date. That would put us
1641 // inside the same year but a strange number of months forward/back..
1642 m_spinYear
->SetValue(target
.GetYear());
1646 // ----------------------------------------------------------------------------
1647 // keyboard interface
1648 // ----------------------------------------------------------------------------
1650 void wxCalendarCtrl::OnChar(wxKeyEvent
& event
)
1653 switch ( event
.GetKeyCode() )
1657 target
= m_date
+ wxDateSpan::Year();
1658 if ( ChangeYear(&target
) )
1660 SetDateAndNotify(target
);
1666 target
= m_date
- wxDateSpan::Year();
1667 if ( ChangeYear(&target
) )
1669 SetDateAndNotify(target
);
1674 target
= m_date
- wxDateSpan::Month();
1675 ChangeMonth(&target
);
1676 SetDateAndNotify(target
); // always
1680 target
= m_date
+ wxDateSpan::Month();
1681 ChangeMonth(&target
);
1682 SetDateAndNotify(target
); // always
1686 if ( event
.ControlDown() )
1688 target
= wxDateTime(m_date
).SetToNextWeekDay(
1689 GetWindowStyle() & wxCAL_MONDAY_FIRST
1690 ? wxDateTime::Sun
: wxDateTime::Sat
);
1691 if ( !IsDateInRange(target
) )
1693 target
= GetUpperDateLimit();
1695 SetDateAndNotify(target
);
1698 SetDateAndNotify(m_date
+ wxDateSpan::Day());
1702 if ( event
.ControlDown() )
1704 target
= wxDateTime(m_date
).SetToPrevWeekDay(
1705 GetWindowStyle() & wxCAL_MONDAY_FIRST
1706 ? wxDateTime::Mon
: wxDateTime::Sun
);
1707 if ( !IsDateInRange(target
) )
1709 target
= GetLowerDateLimit();
1711 SetDateAndNotify(target
);
1714 SetDateAndNotify(m_date
- wxDateSpan::Day());
1718 SetDateAndNotify(m_date
- wxDateSpan::Week());
1722 SetDateAndNotify(m_date
+ wxDateSpan::Week());
1726 if ( event
.ControlDown() )
1727 SetDateAndNotify(wxDateTime::Today());
1729 SetDateAndNotify(wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear()));
1733 SetDateAndNotify(wxDateTime(m_date
).SetToLastMonthDay());
1737 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1745 // ----------------------------------------------------------------------------
1746 // holidays handling
1747 // ----------------------------------------------------------------------------
1749 void wxCalendarCtrl::EnableHolidayDisplay(bool display
)
1751 long style
= GetWindowStyle();
1753 style
|= wxCAL_SHOW_HOLIDAYS
;
1755 style
&= ~wxCAL_SHOW_HOLIDAYS
;
1757 SetWindowStyle(style
);
1762 ResetHolidayAttrs();
1767 void wxCalendarCtrl::SetHolidayAttrs()
1769 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS
)
1771 ResetHolidayAttrs();
1773 wxDateTime::Tm tm
= m_date
.GetTm();
1774 wxDateTime
dtStart(1, tm
.mon
, tm
.year
),
1775 dtEnd
= dtStart
.GetLastMonthDay();
1777 wxDateTimeArray hol
;
1778 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart
, dtEnd
, hol
);
1780 size_t count
= hol
.GetCount();
1781 for ( size_t n
= 0; n
< count
; n
++ )
1783 SetHoliday(hol
[n
].GetDay());
1788 void wxCalendarCtrl::SetHoliday(size_t day
)
1790 wxCHECK_RET( day
> 0 && day
< 32, _T("invalid day in SetHoliday") );
1792 wxCalendarDateAttr
*attr
= GetAttr(day
);
1795 attr
= new wxCalendarDateAttr
;
1798 attr
->SetHoliday(true);
1800 // can't use SetAttr() because it would delete this pointer
1801 m_attrs
[day
- 1] = attr
;
1804 void wxCalendarCtrl::ResetHolidayAttrs()
1806 for ( size_t day
= 0; day
< 31; day
++ )
1810 m_attrs
[day
]->SetHoliday(false);
1818 wxCalendarCtrl::GetClassDefaultAttributes(wxWindowVariant variant
)
1820 // Use the same color scheme as wxListBox
1821 return wxListBox::GetClassDefaultAttributes(variant
);
1824 #endif // wxUSE_CALENDARCTRL