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 SetForegroundColour(*wxBLACK
);
325 SetBackgroundColour(*wxWHITE
);
326 SetFont(*wxSWISS_FONT
);
333 wxCalendarCtrl::~wxCalendarCtrl()
335 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
341 // ----------------------------------------------------------------------------
342 // forward wxWin functions to subcontrols
343 // ----------------------------------------------------------------------------
345 bool wxCalendarCtrl::Destroy()
348 m_staticYear
->Destroy();
350 m_spinYear
->Destroy();
352 m_comboMonth
->Destroy();
354 m_staticMonth
->Destroy();
359 m_staticMonth
= NULL
;
361 return wxControl::Destroy();
364 bool wxCalendarCtrl::Show(bool show
)
366 if ( !wxControl::Show(show
) )
371 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
373 if ( GetMonthControl() )
375 GetMonthControl()->Show(show
);
376 GetYearControl()->Show(show
);
383 bool wxCalendarCtrl::Enable(bool enable
)
385 if ( !wxControl::Enable(enable
) )
390 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
392 GetMonthControl()->Enable(enable
);
393 GetYearControl()->Enable(enable
);
399 // ----------------------------------------------------------------------------
400 // enable/disable month/year controls
401 // ----------------------------------------------------------------------------
403 void wxCalendarCtrl::ShowCurrentControls()
405 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
407 if ( AllowMonthChange() )
409 m_comboMonth
->Show();
410 m_staticMonth
->Hide();
412 if ( AllowYearChange() )
415 m_staticYear
->Hide();
423 m_comboMonth
->Hide();
424 m_staticMonth
->Show();
427 // year change not allowed here
429 m_staticYear
->Show();
433 wxControl
*wxCalendarCtrl::GetMonthControl() const
435 return AllowMonthChange() ? (wxControl
*)m_comboMonth
: (wxControl
*)m_staticMonth
;
438 wxControl
*wxCalendarCtrl::GetYearControl() const
440 return AllowYearChange() ? (wxControl
*)m_spinYear
: (wxControl
*)m_staticYear
;
443 void wxCalendarCtrl::EnableYearChange(bool enable
)
445 if ( enable
!= AllowYearChange() )
447 long style
= GetWindowStyle();
449 style
&= ~wxCAL_NO_YEAR_CHANGE
;
451 style
|= wxCAL_NO_YEAR_CHANGE
;
452 SetWindowStyle(style
);
454 ShowCurrentControls();
455 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
462 void wxCalendarCtrl::EnableMonthChange(bool enable
)
464 if ( enable
!= AllowMonthChange() )
466 long style
= GetWindowStyle();
468 style
&= ~wxCAL_NO_MONTH_CHANGE
;
470 style
|= wxCAL_NO_MONTH_CHANGE
;
471 SetWindowStyle(style
);
473 ShowCurrentControls();
474 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
481 // ----------------------------------------------------------------------------
483 // ----------------------------------------------------------------------------
485 bool wxCalendarCtrl::SetDate(const wxDateTime
& date
)
489 bool sameMonth
= m_date
.GetMonth() == date
.GetMonth(),
490 sameYear
= m_date
.GetYear() == date
.GetYear();
492 if ( IsDateInRange(date
) )
494 if ( sameMonth
&& sameYear
)
496 // just change the day
501 if ( AllowMonthChange() && (AllowYearChange() || sameYear
) )
506 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
508 // update the controls
509 m_comboMonth
->SetSelection(m_date
.GetMonth());
511 if ( AllowYearChange() )
513 if ( !m_userChangedYear
)
514 m_spinYear
->SetValue(m_date
.Format(_T("%Y")));
518 // as the month changed, holidays did too
521 // update the calendar
532 m_userChangedYear
= FALSE
;
537 void wxCalendarCtrl::ChangeDay(const wxDateTime
& date
)
539 if ( m_date
!= date
)
541 // we need to refresh the row containing the old date and the one
542 // containing the new one
543 wxDateTime dateOld
= m_date
;
546 RefreshDate(dateOld
);
548 // if the date is in the same row, it was already drawn correctly
549 if ( GetWeek(m_date
) != GetWeek(dateOld
) )
556 void wxCalendarCtrl::SetDateAndNotify(const wxDateTime
& date
)
558 wxDateTime::Tm tm1
= m_date
.GetTm(),
562 if ( tm1
.year
!= tm2
.year
)
563 type
= wxEVT_CALENDAR_YEAR_CHANGED
;
564 else if ( tm1
.mon
!= tm2
.mon
)
565 type
= wxEVT_CALENDAR_MONTH_CHANGED
;
566 else if ( tm1
.mday
!= tm2
.mday
)
567 type
= wxEVT_CALENDAR_DAY_CHANGED
;
573 GenerateEvents(type
, wxEVT_CALENDAR_SEL_CHANGED
);
577 // ----------------------------------------------------------------------------
579 // ----------------------------------------------------------------------------
581 bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
585 if ( !(date
.IsValid()) || ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : TRUE
) )
597 bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
601 if ( !(date
.IsValid()) || ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : TRUE
) )
613 bool wxCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
/* = wxDefaultDateTime */, const wxDateTime
& upperdate
/* = wxDefaultDateTime */)
618 ( !( lowerdate
.IsValid() ) || ( ( upperdate
.IsValid() ) ? ( lowerdate
<= upperdate
) : TRUE
) ) &&
619 ( !( upperdate
.IsValid() ) || ( ( lowerdate
.IsValid() ) ? ( upperdate
>= lowerdate
) : TRUE
) ) )
621 m_lowdate
= lowerdate
;
622 m_highdate
= upperdate
;
632 // ----------------------------------------------------------------------------
634 // ----------------------------------------------------------------------------
636 wxDateTime
wxCalendarCtrl::GetStartDate() const
638 wxDateTime::Tm tm
= m_date
.GetTm();
640 wxDateTime date
= wxDateTime(1, tm
.mon
, tm
.year
);
643 date
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
644 ? wxDateTime::Mon
: wxDateTime::Sun
);
646 if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
)
648 // We want to offset the calendar if we start on the first..
649 if ( date
.GetDay() == 1 )
651 date
-= wxDateSpan::Week();
658 bool wxCalendarCtrl::IsDateShown(const wxDateTime
& date
) const
660 if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
662 return date
.GetMonth() == m_date
.GetMonth();
670 bool wxCalendarCtrl::IsDateInRange(const wxDateTime
& date
) const
672 // Check if the given date is in the range specified
673 return ( ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : TRUE
)
674 && ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : TRUE
) );
677 bool wxCalendarCtrl::ChangeYear(wxDateTime
* target
) const
681 if ( !(IsDateInRange(*target
)) )
683 if ( target
->GetYear() < m_date
.GetYear() )
685 if ( target
->GetYear() >= GetLowerDateLimit().GetYear() )
687 *target
= GetLowerDateLimit();
697 if ( target
->GetYear() <= GetUpperDateLimit().GetYear() )
699 *target
= GetUpperDateLimit();
716 bool wxCalendarCtrl::ChangeMonth(wxDateTime
* target
) const
720 if ( !(IsDateInRange(*target
)) )
724 if ( target
->GetMonth() < m_date
.GetMonth() )
726 *target
= GetLowerDateLimit();
730 *target
= GetUpperDateLimit();
737 size_t wxCalendarCtrl::GetWeek(const wxDateTime
& date
) const
739 size_t retval
= date
.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
740 ? wxDateTime::Monday_First
741 : wxDateTime::Sunday_First
);
743 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
745 // we need to offset an extra week if we "start" on the 1st of the month
746 wxDateTime::Tm tm
= date
.GetTm();
748 wxDateTime datetest
= wxDateTime(1, tm
.mon
, tm
.year
);
751 datetest
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
752 ? wxDateTime::Mon
: wxDateTime::Sun
);
754 if ( datetest
.GetDay() == 1 )
763 // ----------------------------------------------------------------------------
765 // ----------------------------------------------------------------------------
767 // this is a composite control and it must arrange its parts each time its
768 // size or position changes: the combobox and spinctrl are along the top of
769 // the available area and the calendar takes up therest of the space
771 // the static controls are supposed to be always smaller than combo/spin so we
772 // always use the latter for size calculations and position the static to take
775 // the constants used for the layout
776 #define VERT_MARGIN 5 // distance between combo and calendar
778 #define HORZ_MARGIN 5 // spin
780 #define HORZ_MARGIN 15 // spin
782 wxSize
wxCalendarCtrl::DoGetBestSize() const
784 // calc the size of the calendar
785 ((wxCalendarCtrl
*)this)->RecalcGeometry(); // const_cast
787 wxCoord width
= 7*m_widthCol
,
788 height
= 7*m_heightRow
+ m_rowOffset
+ VERT_MARGIN
;
790 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
792 // the combobox doesn't report its height correctly (it returns the
793 // height including the drop down list) so don't use it
794 height
+= m_spinYear
->GetBestSize().y
;
797 if ( !HasFlag(wxBORDER_NONE
) )
799 // the border would clip the last line otherwise
804 return wxSize(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()
903 if ( m_widthCol
!= 0 )
910 // determine the column width (we assume that the weekday names are always
911 // wider (in any language) than the numbers)
913 wxDateTime::WeekDay wd
;
914 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
917 dc
.GetTextExtent(m_weekdays
[wd
], &width
, &m_heightRow
);
918 if ( width
> m_widthCol
)
924 // leave some margins
928 m_rowOffset
= (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) ? m_heightRow
: 0; // conditional in relation to style
931 // ----------------------------------------------------------------------------
933 // ----------------------------------------------------------------------------
935 void wxCalendarCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
))
944 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
945 m_date
.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
951 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
953 // draw the sequential month-selector
955 dc
.SetBackgroundMode(wxTRANSPARENT
);
956 dc
.SetTextForeground(*wxBLACK
);
957 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
958 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
959 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
961 // Get extent of month-name + year
962 wxCoord monthw
, monthh
;
963 wxString headertext
= m_date
.Format(wxT("%B %Y"));
964 dc
.GetTextExtent(headertext
, &monthw
, &monthh
);
966 // draw month-name centered above weekdays
967 wxCoord monthx
= ((m_widthCol
* 7) - monthw
) / 2;
968 wxCoord monthy
= ((m_heightRow
- monthh
) / 2) + y
;
969 dc
.DrawText(headertext
, monthx
, monthy
);
971 // calculate the "month-arrows"
972 wxPoint leftarrow
[3];
973 wxPoint rightarrow
[3];
975 int arrowheight
= monthh
/ 2;
977 leftarrow
[0] = wxPoint(0, arrowheight
/ 2);
978 leftarrow
[1] = wxPoint(arrowheight
/ 2, 0);
979 leftarrow
[2] = wxPoint(arrowheight
/ 2, arrowheight
- 1);
981 rightarrow
[0] = wxPoint(0, 0);
982 rightarrow
[1] = wxPoint(arrowheight
/ 2, arrowheight
/ 2);
983 rightarrow
[2] = wxPoint(0, arrowheight
- 1);
985 // draw the "month-arrows"
987 wxCoord arrowy
= (m_heightRow
- arrowheight
) / 2;
988 wxCoord larrowx
= (m_widthCol
- (arrowheight
/ 2)) / 2;
989 wxCoord rarrowx
= ((m_widthCol
- (arrowheight
/ 2)) / 2) + m_widthCol
*6;
990 m_leftArrowRect
= wxRect(0, 0, 0, 0);
991 m_rightArrowRect
= wxRect(0, 0, 0, 0);
993 if ( AllowMonthChange() )
995 wxDateTime ldpm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) - wxDateSpan::Day(); // last day prev month
996 // Check if range permits change
997 if ( IsDateInRange(ldpm
) && ( ( ldpm
.GetYear() == m_date
.GetYear() ) ? TRUE
: AllowYearChange() ) )
999 m_leftArrowRect
= wxRect(larrowx
- 3, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1000 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1001 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1002 dc
.DrawPolygon(3, leftarrow
, larrowx
, arrowy
, wxWINDING_RULE
);
1003 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1004 dc
.DrawRectangle(m_leftArrowRect
);
1006 wxDateTime fdnm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) + wxDateSpan::Month(); // first day next month
1007 if ( IsDateInRange(fdnm
) && ( ( fdnm
.GetYear() == m_date
.GetYear() ) ? TRUE
: AllowYearChange() ) )
1009 m_rightArrowRect
= wxRect(rarrowx
- 4, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1010 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1011 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1012 dc
.DrawPolygon(3, rightarrow
, rarrowx
, arrowy
, wxWINDING_RULE
);
1013 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1014 dc
.DrawRectangle(m_rightArrowRect
);
1021 // first draw the week days
1022 if ( IsExposed(0, y
, 7*m_widthCol
, m_heightRow
) )
1025 wxLogDebug("painting the header");
1028 dc
.SetBackgroundMode(wxTRANSPARENT
);
1029 dc
.SetTextForeground(m_colHeaderFg
);
1030 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
1031 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
1032 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
1034 bool startOnMonday
= (GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1035 for ( size_t wd
= 0; wd
< 7; wd
++ )
1038 if ( startOnMonday
)
1039 n
= wd
== 6 ? 0 : wd
+ 1;
1043 dc
.GetTextExtent(m_weekdays
[n
], &dayw
, &dayh
);
1044 dc
.DrawText(m_weekdays
[n
], (wd
*m_widthCol
) + ((m_widthCol
- dayw
) / 2), y
); // center the day-name
1048 // then the calendar itself
1049 dc
.SetTextForeground(*wxBLACK
);
1050 //dc.SetFont(*wxNORMAL_FONT);
1053 wxDateTime date
= GetStartDate();
1056 wxLogDebug("starting calendar from %s\n",
1057 date
.Format("%a %d-%m-%Y %H:%M:%S").c_str());
1060 dc
.SetBackgroundMode(wxSOLID
);
1061 for ( size_t nWeek
= 1; nWeek
<= 6; nWeek
++, y
+= m_heightRow
)
1063 // if the update region doesn't intersect this row, don't paint it
1064 if ( !IsExposed(0, y
, 7*m_widthCol
, m_heightRow
- 1) )
1066 date
+= wxDateSpan::Week();
1072 wxLogDebug("painting week %d at y = %d\n", nWeek
, y
);
1075 for ( size_t wd
= 0; wd
< 7; wd
++ )
1077 if ( IsDateShown(date
) )
1079 // don't use wxDate::Format() which prepends 0s
1080 unsigned int day
= date
.GetDay();
1081 wxString dayStr
= wxString::Format(_T("%u"), day
);
1083 dc
.GetTextExtent(dayStr
, &width
, (wxCoord
*)NULL
);
1085 bool changedColours
= FALSE
,
1086 changedFont
= FALSE
;
1089 wxCalendarDateAttr
*attr
= NULL
;
1091 if ( date
.GetMonth() != m_date
.GetMonth() || !IsDateInRange(date
) )
1093 // surrounding week or out-of-range
1095 dc
.SetTextForeground(*wxLIGHT_GREY
);
1096 changedColours
= TRUE
;
1100 isSel
= date
.IsSameDate(m_date
);
1101 attr
= m_attrs
[day
- 1];
1105 dc
.SetTextForeground(m_colHighlightFg
);
1106 dc
.SetTextBackground(m_colHighlightBg
);
1108 changedColours
= TRUE
;
1112 wxColour colFg
, colBg
;
1114 if ( attr
->IsHoliday() )
1116 colFg
= m_colHolidayFg
;
1117 colBg
= m_colHolidayBg
;
1121 colFg
= attr
->GetTextColour();
1122 colBg
= attr
->GetBackgroundColour();
1127 dc
.SetTextForeground(colFg
);
1128 changedColours
= TRUE
;
1133 dc
.SetTextBackground(colBg
);
1134 changedColours
= TRUE
;
1137 if ( attr
->HasFont() )
1139 dc
.SetFont(attr
->GetFont());
1145 wxCoord x
= wd
*m_widthCol
+ (m_widthCol
- width
) / 2;
1146 dc
.DrawText(dayStr
, x
, y
+ 1);
1148 if ( !isSel
&& attr
&& attr
->HasBorder() )
1151 if ( attr
->HasBorderColour() )
1153 colBorder
= attr
->GetBorderColour();
1157 colBorder
= m_foregroundColour
;
1160 wxPen
pen(colBorder
, 1, wxSOLID
);
1162 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1164 switch ( attr
->GetBorder() )
1166 case wxCAL_BORDER_SQUARE
:
1167 dc
.DrawRectangle(x
- 2, y
,
1168 width
+ 4, m_heightRow
);
1171 case wxCAL_BORDER_ROUND
:
1172 dc
.DrawEllipse(x
- 2, y
,
1173 width
+ 4, m_heightRow
);
1177 wxFAIL_MSG(_T("unknown border type"));
1181 if ( changedColours
)
1183 dc
.SetTextForeground(m_foregroundColour
);
1184 dc
.SetTextBackground(m_backgroundColour
);
1192 //else: just don't draw it
1194 date
+= wxDateSpan::Day();
1198 // Greying out out-of-range background
1199 bool showSurrounding
= (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) != 0;
1201 date
= ( showSurrounding
) ? GetStartDate() : wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear());
1202 if ( !IsDateInRange(date
) )
1204 wxDateTime firstOOR
= GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1206 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1207 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1209 HighlightRange(&dc
, date
, firstOOR
, wxTRANSPARENT_PEN
, &oorbrush
);
1212 date
= ( showSurrounding
) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear());
1213 if ( !IsDateInRange(date
) )
1215 wxDateTime firstOOR
= GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1217 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1218 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1220 HighlightRange(&dc
, firstOOR
, date
, wxTRANSPARENT_PEN
, &oorbrush
);
1224 wxLogDebug("+++ finished painting");
1228 void wxCalendarCtrl::RefreshDate(const wxDateTime
& date
)
1234 // always refresh the whole row at once because our OnPaint() will draw
1235 // the whole row anyhow - and this allows the small optimisation in
1236 // OnClick() below to work
1239 rect
.y
= (m_heightRow
* GetWeek(date
)) + m_rowOffset
;
1241 rect
.width
= 7*m_widthCol
;
1242 rect
.height
= m_heightRow
;
1245 // VZ: for some reason, the selected date seems to occupy more space under
1246 // MSW - this is probably some bug in the font size calculations, but I
1247 // don't know where exactly. This fix is ugly and leads to more
1248 // refreshes than really needed, but without it the selected days
1249 // leaves even more ugly underscores on screen.
1254 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
1257 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
1260 Refresh(TRUE
, &rect
);
1263 void wxCalendarCtrl::HighlightRange(wxPaintDC
* pDC
, const wxDateTime
& fromdate
, const wxDateTime
& todate
, wxPen
* pPen
, wxBrush
* pBrush
)
1265 // Highlights the given range using pen and brush
1266 // Does nothing if todate < fromdate
1270 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate
.Format("%d %m %Y"), todate
.Format("%d %m %Y"));
1273 if ( todate
>= fromdate
)
1280 // implicit: both dates must be currently shown - checked by GetDateCoord
1281 if ( GetDateCoord(fromdate
, &fd
, &fw
) && GetDateCoord(todate
, &td
, &tw
) )
1284 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd
, fw
, td
, tw
);
1286 if ( ( (tw
- fw
) == 1 ) && ( td
< fd
) )
1288 // special case: interval 7 days or less not in same week
1289 // split in two seperate intervals
1290 wxDateTime tfd
= fromdate
+ wxDateSpan::Days(7-fd
);
1291 wxDateTime ftd
= tfd
+ wxDateSpan::Day();
1293 wxLogDebug("Highlight: Seperate segments");
1296 HighlightRange(pDC
, fromdate
, tfd
, pPen
, pBrush
);
1297 HighlightRange(pDC
, ftd
, todate
, pPen
, pBrush
);
1302 wxPoint corners
[8]; // potentially 8 corners in polygon
1306 // simple case: same week
1308 corners
[0] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
);
1309 corners
[1] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1 ) * m_heightRow
) + m_rowOffset
);
1310 corners
[2] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
);
1311 corners
[3] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
);
1316 // "complex" polygon
1317 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1321 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1322 corners
[cidx
] = wxPoint(0, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1325 corners
[cidx
] = wxPoint(0, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1326 corners
[cidx
] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1330 corners
[cidx
] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1331 corners
[cidx
] = wxPoint(7 * m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1334 corners
[cidx
] = wxPoint(7 * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1340 pDC
->SetBrush(*pBrush
);
1342 pDC
->DrawPolygon(numpoints
, corners
);
1348 wxLogDebug("--- HighlightRange ---");
1352 bool wxCalendarCtrl::GetDateCoord(const wxDateTime
& date
, int *day
, int *week
) const
1357 wxLogDebug("+++ GetDateCoord: (%s) +++", date
.Format("%d %m %Y"));
1360 if ( IsDateShown(date
) )
1362 bool startOnMonday
= ( GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1365 *day
= date
.GetWeekDay();
1367 if ( *day
== 0 ) // sunday
1369 *day
= ( startOnMonday
) ? 7 : 1;
1373 *day
+= ( startOnMonday
) ? 0 : 1;
1376 int targetmonth
= date
.GetMonth() + (12 * date
.GetYear());
1377 int thismonth
= m_date
.GetMonth() + (12 * m_date
.GetYear());
1380 if ( targetmonth
== thismonth
)
1382 *week
= GetWeek(date
);
1386 if ( targetmonth
< thismonth
)
1388 *week
= 1; // trivial
1390 else // targetmonth > thismonth
1396 // get the datecoord of the last day in the month currently shown
1398 wxLogDebug(" +++ LDOM +++");
1400 GetDateCoord(ldcm
.SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear()), &lastday
, &lastweek
);
1402 wxLogDebug(" --- LDOM ---");
1405 wxTimeSpan span
= date
- ldcm
;
1407 int daysfromlast
= span
.GetDays();
1409 wxLogDebug("daysfromlast: %i", daysfromlast
);
1411 if ( daysfromlast
+ lastday
> 7 ) // past week boundary
1413 int wholeweeks
= (daysfromlast
/ 7);
1414 *week
= wholeweeks
+ lastweek
;
1415 if ( (daysfromlast
- (7 * wholeweeks
) + lastday
) > 7 )
1435 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date
.Format("%d %m %Y"), *day
, *week
);
1441 // ----------------------------------------------------------------------------
1443 // ----------------------------------------------------------------------------
1445 void wxCalendarCtrl::OnDClick(wxMouseEvent
& event
)
1447 if ( HitTest(event
.GetPosition()) != wxCAL_HITTEST_DAY
)
1453 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1457 void wxCalendarCtrl::OnClick(wxMouseEvent
& event
)
1460 wxDateTime::WeekDay wday
;
1461 switch ( HitTest(event
.GetPosition(), &date
, &wday
) )
1463 case wxCAL_HITTEST_DAY
:
1464 if ( IsDateInRange(date
) )
1468 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED
,
1469 wxEVT_CALENDAR_SEL_CHANGED
);
1473 case wxCAL_HITTEST_HEADER
:
1475 wxCalendarEvent
event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED
);
1476 event
.m_wday
= wday
;
1477 (void)GetEventHandler()->ProcessEvent(event
);
1481 case wxCAL_HITTEST_DECMONTH
:
1482 case wxCAL_HITTEST_INCMONTH
:
1483 case wxCAL_HITTEST_SURROUNDING_WEEK
:
1484 SetDateAndNotify(date
); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1488 wxFAIL_MSG(_T("unknown hittest code"));
1491 case wxCAL_HITTEST_NOWHERE
:
1497 wxCalendarHitTestResult
wxCalendarCtrl::HitTest(const wxPoint
& pos
,
1499 wxDateTime::WeekDay
*wd
)
1505 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1506 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
1510 // we need to find out if the hit is on left arrow, on month or on right arrow
1512 if ( wxRegion(m_leftArrowRect
).Contains(pos
) == wxInRegion
)
1516 if ( IsDateInRange(m_date
- wxDateSpan::Month()) )
1518 *date
= m_date
- wxDateSpan::Month();
1522 *date
= GetLowerDateLimit();
1526 return wxCAL_HITTEST_DECMONTH
;
1529 if ( wxRegion(m_rightArrowRect
).Contains(pos
) == wxInRegion
)
1533 if ( IsDateInRange(m_date
+ wxDateSpan::Month()) )
1535 *date
= m_date
+ wxDateSpan::Month();
1539 *date
= GetUpperDateLimit();
1543 return wxCAL_HITTEST_INCMONTH
;
1548 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1550 int wday
= pos
.x
/ m_widthCol
;
1551 // if ( y < m_heightRow )
1552 if ( y
< (m_heightRow
+ m_rowOffset
) )
1554 if ( y
> m_rowOffset
)
1558 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST
)
1560 wday
= wday
== 6 ? 0 : wday
+ 1;
1563 *wd
= (wxDateTime::WeekDay
)wday
;
1566 return wxCAL_HITTEST_HEADER
;
1570 return wxCAL_HITTEST_NOWHERE
;
1574 // int week = (y - m_heightRow) / m_heightRow;
1575 int week
= (y
- (m_heightRow
+ m_rowOffset
)) / m_heightRow
;
1576 if ( week
>= 6 || wday
>= 7 )
1578 return wxCAL_HITTEST_NOWHERE
;
1581 wxDateTime dt
= GetStartDate() + wxDateSpan::Days(7*week
+ wday
);
1583 if ( IsDateShown(dt
) )
1588 if ( dt
.GetMonth() == m_date
.GetMonth() )
1591 return wxCAL_HITTEST_DAY
;
1595 return wxCAL_HITTEST_SURROUNDING_WEEK
;
1600 return wxCAL_HITTEST_NOWHERE
;
1604 // ----------------------------------------------------------------------------
1605 // subcontrols events handling
1606 // ----------------------------------------------------------------------------
1608 void wxCalendarCtrl::OnMonthChange(wxCommandEvent
& event
)
1610 wxDateTime::Tm tm
= m_date
.GetTm();
1612 wxDateTime::Month mon
= (wxDateTime::Month
)event
.GetInt();
1613 if ( tm
.mday
> wxDateTime::GetNumberOfDays(mon
, tm
.year
) )
1615 tm
.mday
= wxDateTime::GetNumberOfDays(mon
, tm
.year
);
1618 wxDateTime target
= wxDateTime(tm
.mday
, mon
, tm
.year
);
1620 ChangeMonth(&target
);
1621 SetDateAndNotify(target
);
1624 void wxCalendarCtrl::OnYearChange(wxCommandEvent
& event
)
1626 int year
= (int)event
.GetInt();
1627 if ( year
== INT_MIN
)
1629 // invalid year in the spin control, ignore it
1633 wxDateTime::Tm tm
= m_date
.GetTm();
1635 if ( tm
.mday
> wxDateTime::GetNumberOfDays(tm
.mon
, year
) )
1637 tm
.mday
= wxDateTime::GetNumberOfDays(tm
.mon
, year
);
1640 wxDateTime target
= wxDateTime(tm
.mday
, tm
.mon
, year
);
1642 if ( ChangeYear(&target
) )
1644 SetDateAndNotify(target
);
1648 // In this case we don't want to change the date. That would put us
1649 // inside the same year but a strange number of months forward/back..
1650 m_spinYear
->SetValue(target
.GetYear());
1654 // ----------------------------------------------------------------------------
1655 // keyboard interface
1656 // ----------------------------------------------------------------------------
1658 void wxCalendarCtrl::OnChar(wxKeyEvent
& event
)
1661 switch ( event
.GetKeyCode() )
1665 target
= m_date
+ wxDateSpan::Year();
1666 if ( ChangeYear(&target
) )
1668 SetDateAndNotify(target
);
1674 target
= m_date
- wxDateSpan::Year();
1675 if ( ChangeYear(&target
) )
1677 SetDateAndNotify(target
);
1682 target
= m_date
- wxDateSpan::Month();
1683 ChangeMonth(&target
);
1684 SetDateAndNotify(target
); // always
1688 target
= m_date
+ wxDateSpan::Month();
1689 ChangeMonth(&target
);
1690 SetDateAndNotify(target
); // always
1694 if ( event
.ControlDown() )
1696 target
= wxDateTime(m_date
).SetToNextWeekDay(
1697 GetWindowStyle() & wxCAL_MONDAY_FIRST
1698 ? wxDateTime::Sun
: wxDateTime::Sat
);
1699 if ( !IsDateInRange(target
) )
1701 target
= GetUpperDateLimit();
1703 SetDateAndNotify(target
);
1706 SetDateAndNotify(m_date
+ wxDateSpan::Day());
1710 if ( event
.ControlDown() )
1712 target
= wxDateTime(m_date
).SetToPrevWeekDay(
1713 GetWindowStyle() & wxCAL_MONDAY_FIRST
1714 ? wxDateTime::Mon
: wxDateTime::Sun
);
1715 if ( !IsDateInRange(target
) )
1717 target
= GetLowerDateLimit();
1719 SetDateAndNotify(target
);
1722 SetDateAndNotify(m_date
- wxDateSpan::Day());
1726 SetDateAndNotify(m_date
- wxDateSpan::Week());
1730 SetDateAndNotify(m_date
+ wxDateSpan::Week());
1734 if ( event
.ControlDown() )
1735 SetDateAndNotify(wxDateTime::Today());
1737 SetDateAndNotify(wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear()));
1741 SetDateAndNotify(wxDateTime(m_date
).SetToLastMonthDay());
1745 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1753 // ----------------------------------------------------------------------------
1754 // holidays handling
1755 // ----------------------------------------------------------------------------
1757 void wxCalendarCtrl::EnableHolidayDisplay(bool display
)
1759 long style
= GetWindowStyle();
1761 style
|= wxCAL_SHOW_HOLIDAYS
;
1763 style
&= ~wxCAL_SHOW_HOLIDAYS
;
1765 SetWindowStyle(style
);
1770 ResetHolidayAttrs();
1775 void wxCalendarCtrl::SetHolidayAttrs()
1777 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS
)
1779 ResetHolidayAttrs();
1781 wxDateTime::Tm tm
= m_date
.GetTm();
1782 wxDateTime
dtStart(1, tm
.mon
, tm
.year
),
1783 dtEnd
= dtStart
.GetLastMonthDay();
1785 wxDateTimeArray hol
;
1786 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart
, dtEnd
, hol
);
1788 size_t count
= hol
.GetCount();
1789 for ( size_t n
= 0; n
< count
; n
++ )
1791 SetHoliday(hol
[n
].GetDay());
1796 void wxCalendarCtrl::SetHoliday(size_t day
)
1798 wxCHECK_RET( day
> 0 && day
< 32, _T("invalid day in SetHoliday") );
1800 wxCalendarDateAttr
*attr
= GetAttr(day
);
1803 attr
= new wxCalendarDateAttr
;
1806 attr
->SetHoliday(TRUE
);
1808 // can't use SetAttr() because it would delete this pointer
1809 m_attrs
[day
- 1] = attr
;
1812 void wxCalendarCtrl::ResetHolidayAttrs()
1814 for ( size_t day
= 0; day
< 31; day
++ )
1818 m_attrs
[day
]->SetHoliday(FALSE
);
1823 // ----------------------------------------------------------------------------
1825 // ----------------------------------------------------------------------------
1827 void wxCalendarEvent::Init()
1829 m_wday
= wxDateTime::Inv_WeekDay
;
1832 wxCalendarEvent::wxCalendarEvent(wxCalendarCtrl
*cal
, wxEventType type
)
1833 : wxCommandEvent(type
, cal
->GetId())
1835 m_date
= cal
->GetDate();
1836 SetEventObject(cal
);
1839 #endif // wxUSE_CALENDARCTRL