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(wxID_ANY
, wxMonthComboBox::OnMonthChange
)
102 BEGIN_EVENT_TABLE(wxYearSpinCtrl
, wxSpinCtrl
)
103 EVT_TEXT(wxID_ANY
, wxYearSpinCtrl::OnYearTextChange
)
104 EVT_SPINCTRL(wxID_ANY
, 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(), wxID_ANY
,
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(wxDefaultPosition
.x
,
206 wxSIZE_AUTO_WIDTH
|wxSIZE_AUTO_HEIGHT
);
209 wxYearSpinCtrl::wxYearSpinCtrl(wxCalendarCtrl
*cal
)
210 : wxSpinCtrl(cal
->GetParent(), wxID_ANY
,
211 cal
->GetDate().Format(_T("%Y")),
214 wxSP_ARROW_KEYS
| wxCLIP_SIBLINGS
,
215 -4300, 10000, cal
->GetDate().GetYear())
221 // ----------------------------------------------------------------------------
223 // ----------------------------------------------------------------------------
225 wxCalendarCtrl::wxCalendarCtrl(wxWindow
*parent
,
227 const wxDateTime
& date
,
231 const wxString
& name
)
235 (void)Create(parent
, id
, date
, pos
, size
, style
, name
);
238 void wxCalendarCtrl::Init()
243 m_staticMonth
= NULL
;
245 m_userChangedYear
= false;
250 wxDateTime::WeekDay wd
;
251 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
253 m_weekdays
[wd
] = wxDateTime::GetWeekDayName(wd
, wxDateTime::Name_Abbr
);
256 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
261 m_colHighlightFg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
262 m_colHighlightBg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
);
264 m_colHolidayFg
= *wxRED
;
265 // don't set m_colHolidayBg - by default, same as our bg colour
267 m_colHeaderFg
= *wxBLUE
;
268 m_colHeaderBg
= *wxLIGHT_GREY
;
271 bool wxCalendarCtrl::Create(wxWindow
*parent
,
273 const wxDateTime
& date
,
277 const wxString
& name
)
279 if ( !wxControl::Create(parent
, id
, pos
, size
,
280 style
| wxCLIP_CHILDREN
| wxWANTS_CHARS
,
281 wxDefaultValidator
, name
) )
286 // needed to get the arrow keys normally used for the dialog navigation
287 SetWindowStyle(style
| wxWANTS_CHARS
);
289 m_date
= date
.IsValid() ? date
: wxDateTime::Today();
291 m_lowdate
= wxDefaultDateTime
;
292 m_highdate
= wxDefaultDateTime
;
294 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
296 m_spinYear
= new wxYearSpinCtrl(this);
297 m_staticYear
= new wxStaticText(GetParent(), wxID_ANY
, m_date
.Format(_T("%Y")),
298 wxDefaultPosition
, wxDefaultSize
,
301 m_comboMonth
= new wxMonthComboBox(this);
302 m_staticMonth
= new wxStaticText(GetParent(), wxID_ANY
, m_date
.Format(_T("%B")),
303 wxDefaultPosition
, wxDefaultSize
,
307 ShowCurrentControls();
310 if ( size
.x
== wxDefaultSize
.x
|| size
.y
== wxDefaultSize
.y
)
312 sizeReal
= DoGetBestSize();
313 if ( size
.x
!= wxDefaultSize
.x
)
315 if ( size
.y
!= wxDefaultSize
.y
)
323 // we need to set the position as well because the main control position
324 // is not the same as the one specified in pos if we have the controls
326 SetSize(pos
.x
, pos
.y
, sizeReal
.x
, sizeReal
.y
);
328 SetForegroundColour(*wxBLACK
);
329 SetBackgroundColour(*wxWHITE
);
330 SetFont(*wxSWISS_FONT
);
337 wxCalendarCtrl::~wxCalendarCtrl()
339 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
345 // ----------------------------------------------------------------------------
346 // forward wxWin functions to subcontrols
347 // ----------------------------------------------------------------------------
349 bool wxCalendarCtrl::Destroy()
352 m_staticYear
->Destroy();
354 m_spinYear
->Destroy();
356 m_comboMonth
->Destroy();
358 m_staticMonth
->Destroy();
363 m_staticMonth
= NULL
;
365 return wxControl::Destroy();
368 bool wxCalendarCtrl::Show(bool show
)
370 if ( !wxControl::Show(show
) )
375 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
377 if ( GetMonthControl() )
379 GetMonthControl()->Show(show
);
380 GetYearControl()->Show(show
);
387 bool wxCalendarCtrl::Enable(bool enable
)
389 if ( !wxControl::Enable(enable
) )
394 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
396 GetMonthControl()->Enable(enable
);
397 GetYearControl()->Enable(enable
);
403 // ----------------------------------------------------------------------------
404 // enable/disable month/year controls
405 // ----------------------------------------------------------------------------
407 void wxCalendarCtrl::ShowCurrentControls()
409 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
411 if ( AllowMonthChange() )
413 m_comboMonth
->Show();
414 m_staticMonth
->Hide();
416 if ( AllowYearChange() )
419 m_staticYear
->Hide();
427 m_comboMonth
->Hide();
428 m_staticMonth
->Show();
431 // year change not allowed here
433 m_staticYear
->Show();
437 wxControl
*wxCalendarCtrl::GetMonthControl() const
439 return AllowMonthChange() ? (wxControl
*)m_comboMonth
: (wxControl
*)m_staticMonth
;
442 wxControl
*wxCalendarCtrl::GetYearControl() const
444 return AllowYearChange() ? (wxControl
*)m_spinYear
: (wxControl
*)m_staticYear
;
447 void wxCalendarCtrl::EnableYearChange(bool enable
)
449 if ( enable
!= AllowYearChange() )
451 long style
= GetWindowStyle();
453 style
&= ~wxCAL_NO_YEAR_CHANGE
;
455 style
|= wxCAL_NO_YEAR_CHANGE
;
456 SetWindowStyle(style
);
458 ShowCurrentControls();
459 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
466 void wxCalendarCtrl::EnableMonthChange(bool enable
)
468 if ( enable
!= AllowMonthChange() )
470 long style
= GetWindowStyle();
472 style
&= ~wxCAL_NO_MONTH_CHANGE
;
474 style
|= wxCAL_NO_MONTH_CHANGE
;
475 SetWindowStyle(style
);
477 ShowCurrentControls();
478 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
485 // ----------------------------------------------------------------------------
487 // ----------------------------------------------------------------------------
489 bool wxCalendarCtrl::SetDate(const wxDateTime
& date
)
493 bool sameMonth
= m_date
.GetMonth() == date
.GetMonth(),
494 sameYear
= m_date
.GetYear() == date
.GetYear();
496 if ( IsDateInRange(date
) )
498 if ( sameMonth
&& sameYear
)
500 // just change the day
505 if ( AllowMonthChange() && (AllowYearChange() || sameYear
) )
510 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
512 // update the controls
513 m_comboMonth
->SetSelection(m_date
.GetMonth());
515 if ( AllowYearChange() )
517 if ( !m_userChangedYear
)
518 m_spinYear
->SetValue(m_date
.Format(_T("%Y")));
522 // as the month changed, holidays did too
525 // update the calendar
536 m_userChangedYear
= false;
541 void wxCalendarCtrl::ChangeDay(const wxDateTime
& date
)
543 if ( m_date
!= date
)
545 // we need to refresh the row containing the old date and the one
546 // containing the new one
547 wxDateTime dateOld
= m_date
;
550 RefreshDate(dateOld
);
552 // if the date is in the same row, it was already drawn correctly
553 if ( GetWeek(m_date
) != GetWeek(dateOld
) )
560 void wxCalendarCtrl::SetDateAndNotify(const wxDateTime
& date
)
562 wxDateTime::Tm tm1
= m_date
.GetTm(),
566 if ( tm1
.year
!= tm2
.year
)
567 type
= wxEVT_CALENDAR_YEAR_CHANGED
;
568 else if ( tm1
.mon
!= tm2
.mon
)
569 type
= wxEVT_CALENDAR_MONTH_CHANGED
;
570 else if ( tm1
.mday
!= tm2
.mday
)
571 type
= wxEVT_CALENDAR_DAY_CHANGED
;
577 GenerateEvents(type
, wxEVT_CALENDAR_SEL_CHANGED
);
581 // ----------------------------------------------------------------------------
583 // ----------------------------------------------------------------------------
585 bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
589 if ( !(date
.IsValid()) || ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) )
601 bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
605 if ( !(date
.IsValid()) || ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true ) )
617 bool wxCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
/* = wxDefaultDateTime */, const wxDateTime
& upperdate
/* = wxDefaultDateTime */)
622 ( !( lowerdate
.IsValid() ) || ( ( upperdate
.IsValid() ) ? ( lowerdate
<= upperdate
) : true ) ) &&
623 ( !( upperdate
.IsValid() ) || ( ( lowerdate
.IsValid() ) ? ( upperdate
>= lowerdate
) : true ) ) )
625 m_lowdate
= lowerdate
;
626 m_highdate
= upperdate
;
636 // ----------------------------------------------------------------------------
638 // ----------------------------------------------------------------------------
640 wxDateTime
wxCalendarCtrl::GetStartDate() const
642 wxDateTime::Tm tm
= m_date
.GetTm();
644 wxDateTime date
= wxDateTime(1, tm
.mon
, tm
.year
);
647 date
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
648 ? wxDateTime::Mon
: wxDateTime::Sun
);
650 if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
)
652 // We want to offset the calendar if we start on the first..
653 if ( date
.GetDay() == 1 )
655 date
-= wxDateSpan::Week();
662 bool wxCalendarCtrl::IsDateShown(const wxDateTime
& date
) const
664 if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
666 return date
.GetMonth() == m_date
.GetMonth();
674 bool wxCalendarCtrl::IsDateInRange(const wxDateTime
& date
) const
676 // Check if the given date is in the range specified
677 return ( ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : true )
678 && ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : true ) );
681 bool wxCalendarCtrl::ChangeYear(wxDateTime
* target
) const
685 if ( !(IsDateInRange(*target
)) )
687 if ( target
->GetYear() < m_date
.GetYear() )
689 if ( target
->GetYear() >= GetLowerDateLimit().GetYear() )
691 *target
= GetLowerDateLimit();
701 if ( target
->GetYear() <= GetUpperDateLimit().GetYear() )
703 *target
= GetUpperDateLimit();
720 bool wxCalendarCtrl::ChangeMonth(wxDateTime
* target
) const
724 if ( !(IsDateInRange(*target
)) )
728 if ( target
->GetMonth() < m_date
.GetMonth() )
730 *target
= GetLowerDateLimit();
734 *target
= GetUpperDateLimit();
741 size_t wxCalendarCtrl::GetWeek(const wxDateTime
& date
) const
743 size_t retval
= date
.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
744 ? wxDateTime::Monday_First
745 : wxDateTime::Sunday_First
);
747 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
749 // we need to offset an extra week if we "start" on the 1st of the month
750 wxDateTime::Tm tm
= date
.GetTm();
752 wxDateTime datetest
= wxDateTime(1, tm
.mon
, tm
.year
);
755 datetest
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
756 ? wxDateTime::Mon
: wxDateTime::Sun
);
758 if ( datetest
.GetDay() == 1 )
767 // ----------------------------------------------------------------------------
769 // ----------------------------------------------------------------------------
771 // this is a composite control and it must arrange its parts each time its
772 // size or position changes: the combobox and spinctrl are along the top of
773 // the available area and the calendar takes up therest of the space
775 // the static controls are supposed to be always smaller than combo/spin so we
776 // always use the latter for size calculations and position the static to take
779 // the constants used for the layout
780 #define VERT_MARGIN 5 // distance between combo and calendar
782 #define HORZ_MARGIN 5 // spin
784 #define HORZ_MARGIN 15 // spin
786 wxSize
wxCalendarCtrl::DoGetBestSize() const
788 // calc the size of the calendar
789 ((wxCalendarCtrl
*)this)->RecalcGeometry(); // const_cast
791 wxCoord width
= 7*m_widthCol
,
792 height
= 7*m_heightRow
+ m_rowOffset
+ VERT_MARGIN
;
794 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
796 // the combobox doesn't report its height correctly (it returns the
797 // height including the drop down list) so don't use it
798 height
+= m_spinYear
->GetBestSize().y
;
801 if ( !HasFlag(wxBORDER_NONE
) )
803 // the border would clip the last line otherwise
808 return wxSize(width
, height
);
811 void wxCalendarCtrl::DoSetSize(int x
, int y
,
812 int width
, int height
,
815 wxControl::DoSetSize(x
, y
, width
, height
, sizeFlags
);
818 void wxCalendarCtrl::DoMoveWindow(int x
, int y
, int width
, int height
)
822 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
824 wxSize sizeCombo
= m_comboMonth
->GetSize();
825 wxSize sizeStatic
= m_staticMonth
->GetSize();
826 wxSize sizeSpin
= m_spinYear
->GetSize();
827 int dy
= (sizeCombo
.y
- sizeStatic
.y
) / 2;
829 In the calender the size of the combobox for the year
830 is just defined by a margin from the month combobox to
831 the left border. While in wxUniv the year control can't
832 show all 4 digits, in wxMsw it show almost twice as
833 much. Instead the year should use it's best size and be
834 left aligned to the calendar. Just in case the month in
835 any language is longer than it has space in the
836 calendar it is shortend.This way the year always can
839 This patch relies on the fact that a combobox has a
840 good best size implementation. This is not the case
841 with wxMSW but I don't know why.
846 #ifdef __WXUNIVERSAL__
847 if (sizeCombo
.x
+ HORZ_MARGIN
- sizeSpin
.x
> width
)
849 m_comboMonth
->SetSize(x
, y
, width
- HORZ_MARGIN
- sizeSpin
.x
, sizeCombo
.y
);
853 m_comboMonth
->Move(x
, y
);
855 m_staticMonth
->Move(x
, y
+ dy
);
856 m_spinYear
->Move(x
+ width
- sizeSpin
.x
, y
);
857 m_staticYear
->Move(x
+ width
- sizeSpin
.x
, y
+ dy
);
859 m_comboMonth
->Move(x
, y
);
860 m_staticMonth
->SetSize(x
, y
+ dy
, sizeCombo
.x
, sizeStatic
.y
);
862 int xDiff
= sizeCombo
.x
+ HORZ_MARGIN
;
864 m_spinYear
->SetSize(x
+ xDiff
, y
, width
- xDiff
, sizeCombo
.y
);
865 m_staticYear
->SetSize(x
+ xDiff
, y
+ dy
, width
- xDiff
, sizeStatic
.y
);
867 yDiff
= wxMax(sizeSpin
.y
, sizeCombo
.y
) + VERT_MARGIN
;
869 else // no controls on the top
874 wxControl::DoMoveWindow(x
, y
+ yDiff
, width
, height
- yDiff
);
877 void wxCalendarCtrl::DoGetPosition(int *x
, int *y
) const
879 wxControl::DoGetPosition(x
, y
);
881 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
883 // our real top corner is not in this position
886 *y
-= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
891 void wxCalendarCtrl::DoGetSize(int *width
, int *height
) const
893 wxControl::DoGetSize(width
, height
);
895 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
897 // our real height is bigger
898 if ( height
&& GetMonthControl())
900 *height
+= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
905 void wxCalendarCtrl::RecalcGeometry()
907 if ( m_widthCol
!= 0 )
914 // determine the column width (we assume that the weekday names are always
915 // wider (in any language) than the numbers)
917 wxDateTime::WeekDay wd
;
918 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
921 dc
.GetTextExtent(m_weekdays
[wd
], &width
, &m_heightRow
);
922 if ( width
> m_widthCol
)
928 // leave some margins
932 m_rowOffset
= (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) ? m_heightRow
: 0; // conditional in relation to style
935 // ----------------------------------------------------------------------------
937 // ----------------------------------------------------------------------------
939 void wxCalendarCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
))
948 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
949 m_date
.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
955 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
957 // draw the sequential month-selector
959 dc
.SetBackgroundMode(wxTRANSPARENT
);
960 dc
.SetTextForeground(*wxBLACK
);
961 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
962 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
963 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
965 // Get extent of month-name + year
966 wxCoord monthw
, monthh
;
967 wxString headertext
= m_date
.Format(wxT("%B %Y"));
968 dc
.GetTextExtent(headertext
, &monthw
, &monthh
);
970 // draw month-name centered above weekdays
971 wxCoord monthx
= ((m_widthCol
* 7) - monthw
) / 2;
972 wxCoord monthy
= ((m_heightRow
- monthh
) / 2) + y
;
973 dc
.DrawText(headertext
, monthx
, monthy
);
975 // calculate the "month-arrows"
976 wxPoint leftarrow
[3];
977 wxPoint rightarrow
[3];
979 int arrowheight
= monthh
/ 2;
981 leftarrow
[0] = wxPoint(0, arrowheight
/ 2);
982 leftarrow
[1] = wxPoint(arrowheight
/ 2, 0);
983 leftarrow
[2] = wxPoint(arrowheight
/ 2, arrowheight
- 1);
985 rightarrow
[0] = wxPoint(0, 0);
986 rightarrow
[1] = wxPoint(arrowheight
/ 2, arrowheight
/ 2);
987 rightarrow
[2] = wxPoint(0, arrowheight
- 1);
989 // draw the "month-arrows"
991 wxCoord arrowy
= (m_heightRow
- arrowheight
) / 2;
992 wxCoord larrowx
= (m_widthCol
- (arrowheight
/ 2)) / 2;
993 wxCoord rarrowx
= ((m_widthCol
- (arrowheight
/ 2)) / 2) + m_widthCol
*6;
994 m_leftArrowRect
= wxRect(0, 0, 0, 0);
995 m_rightArrowRect
= wxRect(0, 0, 0, 0);
997 if ( AllowMonthChange() )
999 wxDateTime ldpm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) - wxDateSpan::Day(); // last day prev month
1000 // Check if range permits change
1001 if ( IsDateInRange(ldpm
) && ( ( ldpm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
1003 m_leftArrowRect
= wxRect(larrowx
- 3, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1004 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1005 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1006 dc
.DrawPolygon(3, leftarrow
, larrowx
, arrowy
, wxWINDING_RULE
);
1007 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1008 dc
.DrawRectangle(m_leftArrowRect
);
1010 wxDateTime fdnm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) + wxDateSpan::Month(); // first day next month
1011 if ( IsDateInRange(fdnm
) && ( ( fdnm
.GetYear() == m_date
.GetYear() ) ? true : AllowYearChange() ) )
1013 m_rightArrowRect
= wxRect(rarrowx
- 4, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1014 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1015 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1016 dc
.DrawPolygon(3, rightarrow
, rarrowx
, arrowy
, wxWINDING_RULE
);
1017 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1018 dc
.DrawRectangle(m_rightArrowRect
);
1025 // first draw the week days
1026 if ( IsExposed(0, y
, 7*m_widthCol
, m_heightRow
) )
1029 wxLogDebug("painting the header");
1032 dc
.SetBackgroundMode(wxTRANSPARENT
);
1033 dc
.SetTextForeground(m_colHeaderFg
);
1034 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
1035 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
1036 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
1038 bool startOnMonday
= (GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1039 for ( size_t wd
= 0; wd
< 7; wd
++ )
1042 if ( startOnMonday
)
1043 n
= wd
== 6 ? 0 : wd
+ 1;
1047 dc
.GetTextExtent(m_weekdays
[n
], &dayw
, &dayh
);
1048 dc
.DrawText(m_weekdays
[n
], (wd
*m_widthCol
) + ((m_widthCol
- dayw
) / 2), y
); // center the day-name
1052 // then the calendar itself
1053 dc
.SetTextForeground(*wxBLACK
);
1054 //dc.SetFont(*wxNORMAL_FONT);
1057 wxDateTime date
= GetStartDate();
1060 wxLogDebug("starting calendar from %s\n",
1061 date
.Format("%a %d-%m-%Y %H:%M:%S").c_str());
1064 dc
.SetBackgroundMode(wxSOLID
);
1065 for ( size_t nWeek
= 1; nWeek
<= 6; nWeek
++, y
+= m_heightRow
)
1067 // if the update region doesn't intersect this row, don't paint it
1068 if ( !IsExposed(0, y
, 7*m_widthCol
, m_heightRow
- 1) )
1070 date
+= wxDateSpan::Week();
1076 wxLogDebug("painting week %d at y = %d\n", nWeek
, y
);
1079 for ( size_t wd
= 0; wd
< 7; wd
++ )
1081 if ( IsDateShown(date
) )
1083 // don't use wxDate::Format() which prepends 0s
1084 unsigned int day
= date
.GetDay();
1085 wxString dayStr
= wxString::Format(_T("%u"), day
);
1087 dc
.GetTextExtent(dayStr
, &width
, (wxCoord
*)NULL
);
1089 bool changedColours
= false,
1090 changedFont
= false;
1093 wxCalendarDateAttr
*attr
= NULL
;
1095 if ( date
.GetMonth() != m_date
.GetMonth() || !IsDateInRange(date
) )
1097 // surrounding week or out-of-range
1099 dc
.SetTextForeground(*wxLIGHT_GREY
);
1100 changedColours
= true;
1104 isSel
= date
.IsSameDate(m_date
);
1105 attr
= m_attrs
[day
- 1];
1109 dc
.SetTextForeground(m_colHighlightFg
);
1110 dc
.SetTextBackground(m_colHighlightBg
);
1112 changedColours
= true;
1116 wxColour colFg
, colBg
;
1118 if ( attr
->IsHoliday() )
1120 colFg
= m_colHolidayFg
;
1121 colBg
= m_colHolidayBg
;
1125 colFg
= attr
->GetTextColour();
1126 colBg
= attr
->GetBackgroundColour();
1131 dc
.SetTextForeground(colFg
);
1132 changedColours
= true;
1137 dc
.SetTextBackground(colBg
);
1138 changedColours
= true;
1141 if ( attr
->HasFont() )
1143 dc
.SetFont(attr
->GetFont());
1149 wxCoord x
= wd
*m_widthCol
+ (m_widthCol
- width
) / 2;
1150 dc
.DrawText(dayStr
, x
, y
+ 1);
1152 if ( !isSel
&& attr
&& attr
->HasBorder() )
1155 if ( attr
->HasBorderColour() )
1157 colBorder
= attr
->GetBorderColour();
1161 colBorder
= m_foregroundColour
;
1164 wxPen
pen(colBorder
, 1, wxSOLID
);
1166 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1168 switch ( attr
->GetBorder() )
1170 case wxCAL_BORDER_SQUARE
:
1171 dc
.DrawRectangle(x
- 2, y
,
1172 width
+ 4, m_heightRow
);
1175 case wxCAL_BORDER_ROUND
:
1176 dc
.DrawEllipse(x
- 2, y
,
1177 width
+ 4, m_heightRow
);
1181 wxFAIL_MSG(_T("unknown border type"));
1185 if ( changedColours
)
1187 dc
.SetTextForeground(m_foregroundColour
);
1188 dc
.SetTextBackground(m_backgroundColour
);
1196 //else: just don't draw it
1198 date
+= wxDateSpan::Day();
1202 // Greying out out-of-range background
1203 bool showSurrounding
= (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) != 0;
1205 date
= ( showSurrounding
) ? GetStartDate() : wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear());
1206 if ( !IsDateInRange(date
) )
1208 wxDateTime firstOOR
= GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1210 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1211 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1213 HighlightRange(&dc
, date
, firstOOR
, wxTRANSPARENT_PEN
, &oorbrush
);
1216 date
= ( showSurrounding
) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear());
1217 if ( !IsDateInRange(date
) )
1219 wxDateTime firstOOR
= GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1221 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1222 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1224 HighlightRange(&dc
, firstOOR
, date
, wxTRANSPARENT_PEN
, &oorbrush
);
1228 wxLogDebug("+++ finished painting");
1232 void wxCalendarCtrl::RefreshDate(const wxDateTime
& date
)
1238 // always refresh the whole row at once because our OnPaint() will draw
1239 // the whole row anyhow - and this allows the small optimisation in
1240 // OnClick() below to work
1243 rect
.y
= (m_heightRow
* GetWeek(date
)) + m_rowOffset
;
1245 rect
.width
= 7*m_widthCol
;
1246 rect
.height
= m_heightRow
;
1249 // VZ: for some reason, the selected date seems to occupy more space under
1250 // MSW - this is probably some bug in the font size calculations, but I
1251 // don't know where exactly. This fix is ugly and leads to more
1252 // refreshes than really needed, but without it the selected days
1253 // leaves even more ugly underscores on screen.
1258 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
1261 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
1264 Refresh(true, &rect
);
1267 void wxCalendarCtrl::HighlightRange(wxPaintDC
* pDC
, const wxDateTime
& fromdate
, const wxDateTime
& todate
, wxPen
* pPen
, wxBrush
* pBrush
)
1269 // Highlights the given range using pen and brush
1270 // Does nothing if todate < fromdate
1274 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate
.Format("%d %m %Y"), todate
.Format("%d %m %Y"));
1277 if ( todate
>= fromdate
)
1284 // implicit: both dates must be currently shown - checked by GetDateCoord
1285 if ( GetDateCoord(fromdate
, &fd
, &fw
) && GetDateCoord(todate
, &td
, &tw
) )
1288 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd
, fw
, td
, tw
);
1290 if ( ( (tw
- fw
) == 1 ) && ( td
< fd
) )
1292 // special case: interval 7 days or less not in same week
1293 // split in two seperate intervals
1294 wxDateTime tfd
= fromdate
+ wxDateSpan::Days(7-fd
);
1295 wxDateTime ftd
= tfd
+ wxDateSpan::Day();
1297 wxLogDebug("Highlight: Seperate segments");
1300 HighlightRange(pDC
, fromdate
, tfd
, pPen
, pBrush
);
1301 HighlightRange(pDC
, ftd
, todate
, pPen
, pBrush
);
1306 wxPoint corners
[8]; // potentially 8 corners in polygon
1310 // simple case: same week
1312 corners
[0] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
);
1313 corners
[1] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1 ) * m_heightRow
) + m_rowOffset
);
1314 corners
[2] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
);
1315 corners
[3] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
);
1320 // "complex" polygon
1321 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1325 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1326 corners
[cidx
] = wxPoint(0, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1329 corners
[cidx
] = wxPoint(0, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1330 corners
[cidx
] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1334 corners
[cidx
] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1335 corners
[cidx
] = wxPoint(7 * m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1338 corners
[cidx
] = wxPoint(7 * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1344 pDC
->SetBrush(*pBrush
);
1346 pDC
->DrawPolygon(numpoints
, corners
);
1352 wxLogDebug("--- HighlightRange ---");
1356 bool wxCalendarCtrl::GetDateCoord(const wxDateTime
& date
, int *day
, int *week
) const
1361 wxLogDebug("+++ GetDateCoord: (%s) +++", date
.Format("%d %m %Y"));
1364 if ( IsDateShown(date
) )
1366 bool startOnMonday
= ( GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1369 *day
= date
.GetWeekDay();
1371 if ( *day
== 0 ) // sunday
1373 *day
= ( startOnMonday
) ? 7 : 1;
1377 *day
+= ( startOnMonday
) ? 0 : 1;
1380 int targetmonth
= date
.GetMonth() + (12 * date
.GetYear());
1381 int thismonth
= m_date
.GetMonth() + (12 * m_date
.GetYear());
1384 if ( targetmonth
== thismonth
)
1386 *week
= GetWeek(date
);
1390 if ( targetmonth
< thismonth
)
1392 *week
= 1; // trivial
1394 else // targetmonth > thismonth
1400 // get the datecoord of the last day in the month currently shown
1402 wxLogDebug(" +++ LDOM +++");
1404 GetDateCoord(ldcm
.SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear()), &lastday
, &lastweek
);
1406 wxLogDebug(" --- LDOM ---");
1409 wxTimeSpan span
= date
- ldcm
;
1411 int daysfromlast
= span
.GetDays();
1413 wxLogDebug("daysfromlast: %i", daysfromlast
);
1415 if ( daysfromlast
+ lastday
> 7 ) // past week boundary
1417 int wholeweeks
= (daysfromlast
/ 7);
1418 *week
= wholeweeks
+ lastweek
;
1419 if ( (daysfromlast
- (7 * wholeweeks
) + lastday
) > 7 )
1439 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date
.Format("%d %m %Y"), *day
, *week
);
1445 // ----------------------------------------------------------------------------
1447 // ----------------------------------------------------------------------------
1449 void wxCalendarCtrl::OnDClick(wxMouseEvent
& event
)
1451 if ( HitTest(event
.GetPosition()) != wxCAL_HITTEST_DAY
)
1457 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1461 void wxCalendarCtrl::OnClick(wxMouseEvent
& event
)
1464 wxDateTime::WeekDay wday
;
1465 switch ( HitTest(event
.GetPosition(), &date
, &wday
) )
1467 case wxCAL_HITTEST_DAY
:
1468 if ( IsDateInRange(date
) )
1472 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED
,
1473 wxEVT_CALENDAR_SEL_CHANGED
);
1477 case wxCAL_HITTEST_HEADER
:
1479 wxCalendarEvent
event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED
);
1480 event
.m_wday
= wday
;
1481 (void)GetEventHandler()->ProcessEvent(event
);
1485 case wxCAL_HITTEST_DECMONTH
:
1486 case wxCAL_HITTEST_INCMONTH
:
1487 case wxCAL_HITTEST_SURROUNDING_WEEK
:
1488 SetDateAndNotify(date
); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1492 wxFAIL_MSG(_T("unknown hittest code"));
1495 case wxCAL_HITTEST_NOWHERE
:
1501 wxCalendarHitTestResult
wxCalendarCtrl::HitTest(const wxPoint
& pos
,
1503 wxDateTime::WeekDay
*wd
)
1509 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1510 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
1514 // we need to find out if the hit is on left arrow, on month or on right arrow
1516 if ( wxRegion(m_leftArrowRect
).Contains(pos
) == wxInRegion
)
1520 if ( IsDateInRange(m_date
- wxDateSpan::Month()) )
1522 *date
= m_date
- wxDateSpan::Month();
1526 *date
= GetLowerDateLimit();
1530 return wxCAL_HITTEST_DECMONTH
;
1533 if ( wxRegion(m_rightArrowRect
).Contains(pos
) == wxInRegion
)
1537 if ( IsDateInRange(m_date
+ wxDateSpan::Month()) )
1539 *date
= m_date
+ wxDateSpan::Month();
1543 *date
= GetUpperDateLimit();
1547 return wxCAL_HITTEST_INCMONTH
;
1552 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1554 int wday
= pos
.x
/ m_widthCol
;
1555 // if ( y < m_heightRow )
1556 if ( y
< (m_heightRow
+ m_rowOffset
) )
1558 if ( y
> m_rowOffset
)
1562 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST
)
1564 wday
= wday
== 6 ? 0 : wday
+ 1;
1567 *wd
= (wxDateTime::WeekDay
)wday
;
1570 return wxCAL_HITTEST_HEADER
;
1574 return wxCAL_HITTEST_NOWHERE
;
1578 // int week = (y - m_heightRow) / m_heightRow;
1579 int week
= (y
- (m_heightRow
+ m_rowOffset
)) / m_heightRow
;
1580 if ( week
>= 6 || wday
>= 7 )
1582 return wxCAL_HITTEST_NOWHERE
;
1585 wxDateTime dt
= GetStartDate() + wxDateSpan::Days(7*week
+ wday
);
1587 if ( IsDateShown(dt
) )
1592 if ( dt
.GetMonth() == m_date
.GetMonth() )
1595 return wxCAL_HITTEST_DAY
;
1599 return wxCAL_HITTEST_SURROUNDING_WEEK
;
1604 return wxCAL_HITTEST_NOWHERE
;
1608 // ----------------------------------------------------------------------------
1609 // subcontrols events handling
1610 // ----------------------------------------------------------------------------
1612 void wxCalendarCtrl::OnMonthChange(wxCommandEvent
& event
)
1614 wxDateTime::Tm tm
= m_date
.GetTm();
1616 wxDateTime::Month mon
= (wxDateTime::Month
)event
.GetInt();
1617 if ( tm
.mday
> wxDateTime::GetNumberOfDays(mon
, tm
.year
) )
1619 tm
.mday
= wxDateTime::GetNumberOfDays(mon
, tm
.year
);
1622 wxDateTime target
= wxDateTime(tm
.mday
, mon
, tm
.year
);
1624 ChangeMonth(&target
);
1625 SetDateAndNotify(target
);
1628 void wxCalendarCtrl::OnYearChange(wxCommandEvent
& event
)
1630 int year
= (int)event
.GetInt();
1631 if ( year
== INT_MIN
)
1633 // invalid year in the spin control, ignore it
1637 wxDateTime::Tm tm
= m_date
.GetTm();
1639 if ( tm
.mday
> wxDateTime::GetNumberOfDays(tm
.mon
, year
) )
1641 tm
.mday
= wxDateTime::GetNumberOfDays(tm
.mon
, year
);
1644 wxDateTime target
= wxDateTime(tm
.mday
, tm
.mon
, year
);
1646 if ( ChangeYear(&target
) )
1648 SetDateAndNotify(target
);
1652 // In this case we don't want to change the date. That would put us
1653 // inside the same year but a strange number of months forward/back..
1654 m_spinYear
->SetValue(target
.GetYear());
1658 // ----------------------------------------------------------------------------
1659 // keyboard interface
1660 // ----------------------------------------------------------------------------
1662 void wxCalendarCtrl::OnChar(wxKeyEvent
& event
)
1665 switch ( event
.GetKeyCode() )
1669 target
= m_date
+ wxDateSpan::Year();
1670 if ( ChangeYear(&target
) )
1672 SetDateAndNotify(target
);
1678 target
= m_date
- wxDateSpan::Year();
1679 if ( ChangeYear(&target
) )
1681 SetDateAndNotify(target
);
1686 target
= m_date
- wxDateSpan::Month();
1687 ChangeMonth(&target
);
1688 SetDateAndNotify(target
); // always
1692 target
= m_date
+ wxDateSpan::Month();
1693 ChangeMonth(&target
);
1694 SetDateAndNotify(target
); // always
1698 if ( event
.ControlDown() )
1700 target
= wxDateTime(m_date
).SetToNextWeekDay(
1701 GetWindowStyle() & wxCAL_MONDAY_FIRST
1702 ? wxDateTime::Sun
: wxDateTime::Sat
);
1703 if ( !IsDateInRange(target
) )
1705 target
= GetUpperDateLimit();
1707 SetDateAndNotify(target
);
1710 SetDateAndNotify(m_date
+ wxDateSpan::Day());
1714 if ( event
.ControlDown() )
1716 target
= wxDateTime(m_date
).SetToPrevWeekDay(
1717 GetWindowStyle() & wxCAL_MONDAY_FIRST
1718 ? wxDateTime::Mon
: wxDateTime::Sun
);
1719 if ( !IsDateInRange(target
) )
1721 target
= GetLowerDateLimit();
1723 SetDateAndNotify(target
);
1726 SetDateAndNotify(m_date
- wxDateSpan::Day());
1730 SetDateAndNotify(m_date
- wxDateSpan::Week());
1734 SetDateAndNotify(m_date
+ wxDateSpan::Week());
1738 if ( event
.ControlDown() )
1739 SetDateAndNotify(wxDateTime::Today());
1741 SetDateAndNotify(wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear()));
1745 SetDateAndNotify(wxDateTime(m_date
).SetToLastMonthDay());
1749 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1757 // ----------------------------------------------------------------------------
1758 // holidays handling
1759 // ----------------------------------------------------------------------------
1761 void wxCalendarCtrl::EnableHolidayDisplay(bool display
)
1763 long style
= GetWindowStyle();
1765 style
|= wxCAL_SHOW_HOLIDAYS
;
1767 style
&= ~wxCAL_SHOW_HOLIDAYS
;
1769 SetWindowStyle(style
);
1774 ResetHolidayAttrs();
1779 void wxCalendarCtrl::SetHolidayAttrs()
1781 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS
)
1783 ResetHolidayAttrs();
1785 wxDateTime::Tm tm
= m_date
.GetTm();
1786 wxDateTime
dtStart(1, tm
.mon
, tm
.year
),
1787 dtEnd
= dtStart
.GetLastMonthDay();
1789 wxDateTimeArray hol
;
1790 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart
, dtEnd
, hol
);
1792 size_t count
= hol
.GetCount();
1793 for ( size_t n
= 0; n
< count
; n
++ )
1795 SetHoliday(hol
[n
].GetDay());
1800 void wxCalendarCtrl::SetHoliday(size_t day
)
1802 wxCHECK_RET( day
> 0 && day
< 32, _T("invalid day in SetHoliday") );
1804 wxCalendarDateAttr
*attr
= GetAttr(day
);
1807 attr
= new wxCalendarDateAttr
;
1810 attr
->SetHoliday(true);
1812 // can't use SetAttr() because it would delete this pointer
1813 m_attrs
[day
- 1] = attr
;
1816 void wxCalendarCtrl::ResetHolidayAttrs()
1818 for ( size_t day
= 0; day
< 31; day
++ )
1822 m_attrs
[day
]->SetHoliday(false);
1827 // ----------------------------------------------------------------------------
1829 // ----------------------------------------------------------------------------
1831 void wxCalendarEvent::Init()
1833 m_wday
= wxDateTime::Inv_WeekDay
;
1836 wxCalendarEvent::wxCalendarEvent(wxCalendarCtrl
*cal
, wxEventType type
)
1837 : wxCommandEvent(type
, cal
->GetId())
1839 m_date
= cal
->GetDate();
1840 SetEventObject(cal
);
1843 #endif // wxUSE_CALENDARCTRL