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(wxNO_BORDER
)
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(wxNO_FULL_REPAINT_ON_RESIZE
)
134 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
135 wxFLAGS_MEMBER(wxVSCROLL
)
136 wxFLAGS_MEMBER(wxHSCROLL
)
138 wxFLAGS_MEMBER(wxCAL_SUNDAY_FIRST
)
139 wxFLAGS_MEMBER(wxCAL_MONDAY_FIRST
)
140 wxFLAGS_MEMBER(wxCAL_SHOW_HOLIDAYS
)
141 wxFLAGS_MEMBER(wxCAL_NO_YEAR_CHANGE
)
142 wxFLAGS_MEMBER(wxCAL_NO_MONTH_CHANGE
)
143 wxFLAGS_MEMBER(wxCAL_SEQUENTIAL_MONTH_SELECTION
)
144 wxFLAGS_MEMBER(wxCAL_SHOW_SURROUNDING_WEEKS
)
146 wxEND_FLAGS( wxCalendarCtrlStyle
)
148 IMPLEMENT_DYNAMIC_CLASS_XTI(wxCalendarCtrl
, wxControl
,"wx/calctrl.h")
150 wxBEGIN_PROPERTIES_TABLE(wxCalendarCtrl
)
151 wxEVENT_RANGE_PROPERTY( Updated
, wxEVT_CALENDAR_SEL_CHANGED
, wxEVT_CALENDAR_WEEKDAY_CLICKED
, wxCalendarEvent
)
152 wxHIDE_PROPERTY( Children
)
153 wxPROPERTY( Date
,wxDateTime
, SetDate
, GetDate
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
154 wxPROPERTY_FLAGS( WindowStyle
, wxCalendarCtrlStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
155 wxEND_PROPERTIES_TABLE()
157 wxBEGIN_HANDLERS_TABLE(wxCalendarCtrl
)
158 wxEND_HANDLERS_TABLE()
160 wxCONSTRUCTOR_6( wxCalendarCtrl
, wxWindow
* , Parent
, wxWindowID
, Id
, wxDateTime
, Date
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
162 IMPLEMENT_DYNAMIC_CLASS(wxCalendarCtrl
, wxControl
)
164 IMPLEMENT_DYNAMIC_CLASS(wxCalendarEvent
, wxCommandEvent
)
166 // ----------------------------------------------------------------------------
168 // ----------------------------------------------------------------------------
170 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_SEL_CHANGED
)
171 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DAY_CHANGED
)
172 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_MONTH_CHANGED
)
173 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_YEAR_CHANGED
)
174 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DOUBLECLICKED
)
175 DEFINE_EVENT_TYPE(wxEVT_CALENDAR_WEEKDAY_CLICKED
)
177 // ============================================================================
179 // ============================================================================
181 // ----------------------------------------------------------------------------
182 // wxMonthComboBox and wxYearSpinCtrl
183 // ----------------------------------------------------------------------------
185 wxMonthComboBox::wxMonthComboBox(wxCalendarCtrl
*cal
)
186 : wxComboBox(cal
->GetParent(), -1,
191 wxCB_READONLY
| wxCLIP_SIBLINGS
)
196 for ( m
= wxDateTime::Jan
; m
< wxDateTime::Inv_Month
; wxNextMonth(m
) )
198 Append(wxDateTime::GetMonthName(m
));
201 SetSelection(m_cal
->GetDate().GetMonth());
202 SetSize(-1, -1, -1, -1, wxSIZE_AUTO_WIDTH
|wxSIZE_AUTO_HEIGHT
);
205 wxYearSpinCtrl::wxYearSpinCtrl(wxCalendarCtrl
*cal
)
206 : wxSpinCtrl(cal
->GetParent(), -1,
207 cal
->GetDate().Format(_T("%Y")),
210 wxSP_ARROW_KEYS
| wxCLIP_SIBLINGS
,
211 -4300, 10000, cal
->GetDate().GetYear())
217 // ----------------------------------------------------------------------------
219 // ----------------------------------------------------------------------------
221 wxCalendarCtrl::wxCalendarCtrl(wxWindow
*parent
,
223 const wxDateTime
& date
,
227 const wxString
& name
)
231 (void)Create(parent
, id
, date
, pos
, size
, style
, name
);
234 void wxCalendarCtrl::Init()
239 m_staticMonth
= NULL
;
241 m_userChangedYear
= FALSE
;
246 wxDateTime::WeekDay wd
;
247 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
249 m_weekdays
[wd
] = wxDateTime::GetWeekDayName(wd
, wxDateTime::Name_Abbr
);
252 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
257 m_colHighlightFg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
);
258 m_colHighlightBg
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
);
260 m_colHolidayFg
= *wxRED
;
261 // don't set m_colHolidayBg - by default, same as our bg colour
263 m_colHeaderFg
= *wxBLUE
;
264 m_colHeaderBg
= *wxLIGHT_GREY
;
267 bool wxCalendarCtrl::Create(wxWindow
*parent
,
269 const wxDateTime
& date
,
273 const wxString
& name
)
275 if ( !wxControl::Create(parent
, id
, pos
, size
,
276 style
| wxCLIP_CHILDREN
| wxWANTS_CHARS
,
277 wxDefaultValidator
, name
) )
282 // needed to get the arrow keys normally used for the dialog navigation
283 SetWindowStyle(style
| wxWANTS_CHARS
);
285 m_date
= date
.IsValid() ? date
: wxDateTime::Today();
287 m_lowdate
= wxDefaultDateTime
;
288 m_highdate
= wxDefaultDateTime
;
290 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
292 m_spinYear
= new wxYearSpinCtrl(this);
293 m_staticYear
= new wxStaticText(GetParent(), -1, m_date
.Format(_T("%Y")),
294 wxDefaultPosition
, wxDefaultSize
,
297 m_comboMonth
= new wxMonthComboBox(this);
298 m_staticMonth
= new wxStaticText(GetParent(), -1, m_date
.Format(_T("%B")),
299 wxDefaultPosition
, wxDefaultSize
,
303 ShowCurrentControls();
306 if ( size
.x
== -1 || size
.y
== -1 )
308 sizeReal
= DoGetBestSize();
319 // we need to set the position as well because the main control position
320 // is not the same as the one specified in pos if we have the controls
322 SetSize(pos
.x
, pos
.y
, sizeReal
.x
, sizeReal
.y
);
324 SetBackgroundColour(*wxWHITE
);
325 SetFont(*wxSWISS_FONT
);
332 wxCalendarCtrl::~wxCalendarCtrl()
334 for ( size_t n
= 0; n
< WXSIZEOF(m_attrs
); n
++ )
340 // ----------------------------------------------------------------------------
341 // forward wxWin functions to subcontrols
342 // ----------------------------------------------------------------------------
344 bool wxCalendarCtrl::Destroy()
347 m_staticYear
->Destroy();
349 m_spinYear
->Destroy();
351 m_comboMonth
->Destroy();
353 m_staticMonth
->Destroy();
358 m_staticMonth
= NULL
;
360 return wxControl::Destroy();
363 bool wxCalendarCtrl::Show(bool show
)
365 if ( !wxControl::Show(show
) )
370 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
372 if ( GetMonthControl() )
374 GetMonthControl()->Show(show
);
375 GetYearControl()->Show(show
);
382 bool wxCalendarCtrl::Enable(bool enable
)
384 if ( !wxControl::Enable(enable
) )
389 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
391 GetMonthControl()->Enable(enable
);
392 GetYearControl()->Enable(enable
);
398 // ----------------------------------------------------------------------------
399 // enable/disable month/year controls
400 // ----------------------------------------------------------------------------
402 void wxCalendarCtrl::ShowCurrentControls()
404 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
406 if ( AllowMonthChange() )
408 m_comboMonth
->Show();
409 m_staticMonth
->Hide();
411 if ( AllowYearChange() )
414 m_staticYear
->Hide();
422 m_comboMonth
->Hide();
423 m_staticMonth
->Show();
426 // year change not allowed here
428 m_staticYear
->Show();
432 wxControl
*wxCalendarCtrl::GetMonthControl() const
434 return AllowMonthChange() ? (wxControl
*)m_comboMonth
: (wxControl
*)m_staticMonth
;
437 wxControl
*wxCalendarCtrl::GetYearControl() const
439 return AllowYearChange() ? (wxControl
*)m_spinYear
: (wxControl
*)m_staticYear
;
442 void wxCalendarCtrl::EnableYearChange(bool enable
)
444 if ( enable
!= AllowYearChange() )
446 long style
= GetWindowStyle();
448 style
&= ~wxCAL_NO_YEAR_CHANGE
;
450 style
|= wxCAL_NO_YEAR_CHANGE
;
451 SetWindowStyle(style
);
453 ShowCurrentControls();
454 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
461 void wxCalendarCtrl::EnableMonthChange(bool enable
)
463 if ( enable
!= AllowMonthChange() )
465 long style
= GetWindowStyle();
467 style
&= ~wxCAL_NO_MONTH_CHANGE
;
469 style
|= wxCAL_NO_MONTH_CHANGE
;
470 SetWindowStyle(style
);
472 ShowCurrentControls();
473 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
)
480 // ----------------------------------------------------------------------------
482 // ----------------------------------------------------------------------------
484 bool wxCalendarCtrl::SetDate(const wxDateTime
& date
)
488 bool sameMonth
= m_date
.GetMonth() == date
.GetMonth(),
489 sameYear
= m_date
.GetYear() == date
.GetYear();
491 if ( IsDateInRange(date
) )
493 if ( sameMonth
&& sameYear
)
495 // just change the day
500 if ( AllowMonthChange() && (AllowYearChange() || sameYear
) )
505 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
507 // update the controls
508 m_comboMonth
->SetSelection(m_date
.GetMonth());
510 if ( AllowYearChange() )
512 if ( !m_userChangedYear
)
513 m_spinYear
->SetValue(m_date
.Format(_T("%Y")));
517 // as the month changed, holidays did too
520 // update the calendar
531 m_userChangedYear
= FALSE
;
536 void wxCalendarCtrl::ChangeDay(const wxDateTime
& date
)
538 if ( m_date
!= date
)
540 // we need to refresh the row containing the old date and the one
541 // containing the new one
542 wxDateTime dateOld
= m_date
;
545 RefreshDate(dateOld
);
547 // if the date is in the same row, it was already drawn correctly
548 if ( GetWeek(m_date
) != GetWeek(dateOld
) )
555 void wxCalendarCtrl::SetDateAndNotify(const wxDateTime
& date
)
557 wxDateTime::Tm tm1
= m_date
.GetTm(),
561 if ( tm1
.year
!= tm2
.year
)
562 type
= wxEVT_CALENDAR_YEAR_CHANGED
;
563 else if ( tm1
.mon
!= tm2
.mon
)
564 type
= wxEVT_CALENDAR_MONTH_CHANGED
;
565 else if ( tm1
.mday
!= tm2
.mday
)
566 type
= wxEVT_CALENDAR_DAY_CHANGED
;
572 GenerateEvents(type
, wxEVT_CALENDAR_SEL_CHANGED
);
576 // ----------------------------------------------------------------------------
578 // ----------------------------------------------------------------------------
580 bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
584 if ( !(date
.IsValid()) || ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : TRUE
) )
596 bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime
& date
/* = wxDefaultDateTime */)
600 if ( !(date
.IsValid()) || ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : TRUE
) )
612 bool wxCalendarCtrl::SetDateRange(const wxDateTime
& lowerdate
/* = wxDefaultDateTime */, const wxDateTime
& upperdate
/* = wxDefaultDateTime */)
617 ( !( lowerdate
.IsValid() ) || ( ( upperdate
.IsValid() ) ? ( lowerdate
<= upperdate
) : TRUE
) ) &&
618 ( !( upperdate
.IsValid() ) || ( ( lowerdate
.IsValid() ) ? ( upperdate
>= lowerdate
) : TRUE
) ) )
620 m_lowdate
= lowerdate
;
621 m_highdate
= upperdate
;
631 // ----------------------------------------------------------------------------
633 // ----------------------------------------------------------------------------
635 wxDateTime
wxCalendarCtrl::GetStartDate() const
637 wxDateTime::Tm tm
= m_date
.GetTm();
639 wxDateTime date
= wxDateTime(1, tm
.mon
, tm
.year
);
642 date
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
643 ? wxDateTime::Mon
: wxDateTime::Sun
);
645 if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
)
647 // We want to offset the calendar if we start on the first..
648 if ( date
.GetDay() == 1 )
650 date
-= wxDateSpan::Week();
657 bool wxCalendarCtrl::IsDateShown(const wxDateTime
& date
) const
659 if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
661 return date
.GetMonth() == m_date
.GetMonth();
669 bool wxCalendarCtrl::IsDateInRange(const wxDateTime
& date
) const
672 // Check if the given date is in the range specified
673 retval
= ( ( ( m_lowdate
.IsValid() ) ? ( date
>= m_lowdate
) : TRUE
)
674 && ( ( m_highdate
.IsValid() ) ? ( date
<= m_highdate
) : TRUE
) );
678 bool wxCalendarCtrl::ChangeYear(wxDateTime
* target
) const
682 if ( !(IsDateInRange(*target
)) )
684 if ( target
->GetYear() < m_date
.GetYear() )
686 if ( target
->GetYear() >= GetLowerDateLimit().GetYear() )
688 *target
= GetLowerDateLimit();
698 if ( target
->GetYear() <= GetUpperDateLimit().GetYear() )
700 *target
= GetUpperDateLimit();
717 bool wxCalendarCtrl::ChangeMonth(wxDateTime
* target
) const
721 if ( !(IsDateInRange(*target
)) )
725 if ( target
->GetMonth() < m_date
.GetMonth() )
727 *target
= GetLowerDateLimit();
731 *target
= GetUpperDateLimit();
738 size_t wxCalendarCtrl::GetWeek(const wxDateTime
& date
) const
740 size_t retval
= date
.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
741 ? wxDateTime::Monday_First
742 : wxDateTime::Sunday_First
);
744 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) )
746 // we need to offset an extra week if we "start" on the 1st of the month
747 wxDateTime::Tm tm
= date
.GetTm();
749 wxDateTime datetest
= wxDateTime(1, tm
.mon
, tm
.year
);
752 datetest
.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
753 ? wxDateTime::Mon
: wxDateTime::Sun
);
755 if ( datetest
.GetDay() == 1 )
764 // ----------------------------------------------------------------------------
766 // ----------------------------------------------------------------------------
768 // this is a composite control and it must arrange its parts each time its
769 // size or position changes: the combobox and spinctrl are along the top of
770 // the available area and the calendar takes up therest of the space
772 // the static controls are supposed to be always smaller than combo/spin so we
773 // always use the latter for size calculations and position the static to take
776 // the constants used for the layout
777 #define VERT_MARGIN 5 // distance between combo and calendar
779 #define HORZ_MARGIN 5 // spin
781 #define HORZ_MARGIN 15 // spin
783 wxSize
wxCalendarCtrl::DoGetBestSize() const
785 // calc the size of the calendar
786 ((wxCalendarCtrl
*)this)->RecalcGeometry(); // const_cast
788 wxCoord width
= 7*m_widthCol
,
789 height
= 7*m_heightRow
+ m_rowOffset
+ VERT_MARGIN
;
791 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
793 // the combobox doesn't report its height correctly (it returns the
794 // height including the drop down list) so don't use it
795 height
+= m_spinYear
->GetBestSize().y
;
798 if ( !HasFlag(wxBORDER_NONE
) )
800 // the border would clip the last line otherwise
805 return wxSize(width
, height
);
808 void wxCalendarCtrl::DoSetSize(int x
, int y
,
809 int width
, int height
,
812 wxControl::DoSetSize(x
, y
, width
, height
, sizeFlags
);
815 void wxCalendarCtrl::DoMoveWindow(int x
, int y
, int width
, int height
)
819 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
821 wxSize sizeCombo
= m_comboMonth
->GetSize();
822 wxSize sizeStatic
= m_staticMonth
->GetSize();
823 wxSize sizeSpin
= m_spinYear
->GetSize();
824 int dy
= (sizeCombo
.y
- sizeStatic
.y
) / 2;
826 In the calender the size of the combobox for the year
827 is just defined by a margin from the month combobox to
828 the left border. While in wxUniv the year control can't
829 show all 4 digits, in wxMsw it show almost twice as
830 much. Instead the year should use it's best size and be
831 left aligned to the calendar. Just in case the month in
832 any language is longer than it has space in the
833 calendar it is shortend.This way the year always can
836 This patch relies on the fact that a combobox has a
837 good best size implementation. This is not the case
838 with wxMSW but I don't know why.
843 #ifdef __WXUNIVERSAL__
844 if (sizeCombo
.x
+ HORZ_MARGIN
- sizeSpin
.x
> width
)
846 m_comboMonth
->SetSize(x
, y
, width
- HORZ_MARGIN
- sizeSpin
.x
, sizeCombo
.y
);
850 m_comboMonth
->Move(x
, y
);
852 m_staticMonth
->Move(x
, y
+ dy
);
853 m_spinYear
->Move(x
+ width
- sizeSpin
.x
, y
);
854 m_staticYear
->Move(x
+ width
- sizeSpin
.x
, y
+ dy
);
856 m_comboMonth
->Move(x
, y
);
857 m_staticMonth
->SetSize(x
, y
+ dy
, sizeCombo
.x
, sizeStatic
.y
);
859 int xDiff
= sizeCombo
.x
+ HORZ_MARGIN
;
861 m_spinYear
->SetSize(x
+ xDiff
, y
, width
- xDiff
, sizeCombo
.y
);
862 m_staticYear
->SetSize(x
+ xDiff
, y
+ dy
, width
- xDiff
, sizeStatic
.y
);
864 yDiff
= wxMax(sizeSpin
.y
, sizeCombo
.y
) + VERT_MARGIN
;
866 else // no controls on the top
871 wxControl::DoMoveWindow(x
, y
+ yDiff
, width
, height
- yDiff
);
874 void wxCalendarCtrl::DoGetPosition(int *x
, int *y
) const
876 wxControl::DoGetPosition(x
, y
);
878 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
880 // our real top corner is not in this position
883 *y
-= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
888 void wxCalendarCtrl::DoGetSize(int *width
, int *height
) const
890 wxControl::DoGetSize(width
, height
);
892 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
894 // our real height is bigger
895 if ( height
&& GetMonthControl())
897 *height
+= GetMonthControl()->GetSize().y
+ VERT_MARGIN
;
902 void wxCalendarCtrl::RecalcGeometry()
904 if ( m_widthCol
!= 0 )
911 // determine the column width (we assume that the weekday names are always
912 // wider (in any language) than the numbers)
914 wxDateTime::WeekDay wd
;
915 for ( wd
= wxDateTime::Sun
; wd
< wxDateTime::Inv_WeekDay
; wxNextWDay(wd
) )
918 dc
.GetTextExtent(m_weekdays
[wd
], &width
, &m_heightRow
);
919 if ( width
> m_widthCol
)
925 // leave some margins
929 m_rowOffset
= (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) ? m_heightRow
: 0; // conditional in relation to style
932 // ----------------------------------------------------------------------------
934 // ----------------------------------------------------------------------------
936 void wxCalendarCtrl::OnPaint(wxPaintEvent
& WXUNUSED(event
))
945 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
946 m_date
.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
952 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
954 // draw the sequential month-selector
956 dc
.SetBackgroundMode(wxTRANSPARENT
);
957 dc
.SetTextForeground(*wxBLACK
);
958 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
959 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
960 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
962 // Get extent of month-name + year
963 wxCoord monthw
, monthh
;
964 wxString headertext
= m_date
.Format(wxT("%B %Y"));
965 dc
.GetTextExtent(headertext
, &monthw
, &monthh
);
967 // draw month-name centered above weekdays
968 wxCoord monthx
= ((m_widthCol
* 7) - monthw
) / 2;
969 wxCoord monthy
= ((m_heightRow
- monthh
) / 2) + y
;
970 dc
.DrawText(headertext
, monthx
, monthy
);
972 // calculate the "month-arrows"
973 wxPoint leftarrow
[3];
974 wxPoint rightarrow
[3];
976 int arrowheight
= monthh
/ 2;
978 leftarrow
[0] = wxPoint(0, arrowheight
/ 2);
979 leftarrow
[1] = wxPoint(arrowheight
/ 2, 0);
980 leftarrow
[2] = wxPoint(arrowheight
/ 2, arrowheight
- 1);
982 rightarrow
[0] = wxPoint(0, 0);
983 rightarrow
[1] = wxPoint(arrowheight
/ 2, arrowheight
/ 2);
984 rightarrow
[2] = wxPoint(0, arrowheight
- 1);
986 // draw the "month-arrows"
988 wxCoord arrowy
= (m_heightRow
- arrowheight
) / 2;
989 wxCoord larrowx
= (m_widthCol
- (arrowheight
/ 2)) / 2;
990 wxCoord rarrowx
= ((m_widthCol
- (arrowheight
/ 2)) / 2) + m_widthCol
*6;
991 m_leftArrowRect
= wxRect(0, 0, 0, 0);
992 m_rightArrowRect
= wxRect(0, 0, 0, 0);
994 if ( AllowMonthChange() )
996 wxDateTime ldpm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) - wxDateSpan::Day(); // last day prev month
997 // Check if range permits change
998 if ( IsDateInRange(ldpm
) && ( ( ldpm
.GetYear() == m_date
.GetYear() ) ? TRUE
: AllowYearChange() ) )
1000 m_leftArrowRect
= wxRect(larrowx
- 3, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1001 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1002 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1003 dc
.DrawPolygon(3, leftarrow
, larrowx
, arrowy
, wxWINDING_RULE
);
1004 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1005 dc
.DrawRectangle(m_leftArrowRect
);
1007 wxDateTime fdnm
= wxDateTime(1,m_date
.GetMonth(), m_date
.GetYear()) + wxDateSpan::Month(); // first day next month
1008 if ( IsDateInRange(fdnm
) && ( ( fdnm
.GetYear() == m_date
.GetYear() ) ? TRUE
: AllowYearChange() ) )
1010 m_rightArrowRect
= wxRect(rarrowx
- 4, arrowy
- 3, (arrowheight
/ 2) + 8, (arrowheight
+ 6));
1011 dc
.SetBrush(wxBrush(*wxBLACK
, wxSOLID
));
1012 dc
.SetPen(wxPen(*wxBLACK
, 1, wxSOLID
));
1013 dc
.DrawPolygon(3, rightarrow
, rarrowx
, arrowy
, wxWINDING_RULE
);
1014 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1015 dc
.DrawRectangle(m_rightArrowRect
);
1022 // first draw the week days
1023 if ( IsExposed(0, y
, 7*m_widthCol
, m_heightRow
) )
1026 wxLogDebug("painting the header");
1029 dc
.SetBackgroundMode(wxTRANSPARENT
);
1030 dc
.SetTextForeground(m_colHeaderFg
);
1031 dc
.SetBrush(wxBrush(m_colHeaderBg
, wxSOLID
));
1032 dc
.SetPen(wxPen(m_colHeaderBg
, 1, wxSOLID
));
1033 dc
.DrawRectangle(0, y
, GetClientSize().x
, m_heightRow
);
1035 bool startOnMonday
= (GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1036 for ( size_t wd
= 0; wd
< 7; wd
++ )
1039 if ( startOnMonday
)
1040 n
= wd
== 6 ? 0 : wd
+ 1;
1044 dc
.GetTextExtent(m_weekdays
[n
], &dayw
, &dayh
);
1045 dc
.DrawText(m_weekdays
[n
], (wd
*m_widthCol
) + ((m_widthCol
- dayw
) / 2), y
); // center the day-name
1049 // then the calendar itself
1050 dc
.SetTextForeground(*wxBLACK
);
1051 //dc.SetFont(*wxNORMAL_FONT);
1054 wxDateTime date
= GetStartDate();
1057 wxLogDebug("starting calendar from %s\n",
1058 date
.Format("%a %d-%m-%Y %H:%M:%S").c_str());
1061 dc
.SetBackgroundMode(wxSOLID
);
1062 for ( size_t nWeek
= 1; nWeek
<= 6; nWeek
++, y
+= m_heightRow
)
1064 // if the update region doesn't intersect this row, don't paint it
1065 if ( !IsExposed(0, y
, 7*m_widthCol
, m_heightRow
- 1) )
1067 date
+= wxDateSpan::Week();
1073 wxLogDebug("painting week %d at y = %d\n", nWeek
, y
);
1076 for ( size_t wd
= 0; wd
< 7; wd
++ )
1078 if ( IsDateShown(date
) )
1080 // don't use wxDate::Format() which prepends 0s
1081 unsigned int day
= date
.GetDay();
1082 wxString dayStr
= wxString::Format(_T("%u"), day
);
1084 dc
.GetTextExtent(dayStr
, &width
, (wxCoord
*)NULL
);
1086 bool changedColours
= FALSE
,
1087 changedFont
= FALSE
;
1090 wxCalendarDateAttr
*attr
= NULL
;
1092 if ( date
.GetMonth() != m_date
.GetMonth() || !IsDateInRange(date
) )
1094 // surrounding week or out-of-range
1096 dc
.SetTextForeground(*wxLIGHT_GREY
);
1097 changedColours
= TRUE
;
1101 isSel
= date
.IsSameDate(m_date
);
1102 attr
= m_attrs
[day
- 1];
1106 dc
.SetTextForeground(m_colHighlightFg
);
1107 dc
.SetTextBackground(m_colHighlightBg
);
1109 changedColours
= TRUE
;
1113 wxColour colFg
, colBg
;
1115 if ( attr
->IsHoliday() )
1117 colFg
= m_colHolidayFg
;
1118 colBg
= m_colHolidayBg
;
1122 colFg
= attr
->GetTextColour();
1123 colBg
= attr
->GetBackgroundColour();
1128 dc
.SetTextForeground(colFg
);
1129 changedColours
= TRUE
;
1134 dc
.SetTextBackground(colBg
);
1135 changedColours
= TRUE
;
1138 if ( attr
->HasFont() )
1140 dc
.SetFont(attr
->GetFont());
1146 wxCoord x
= wd
*m_widthCol
+ (m_widthCol
- width
) / 2;
1147 dc
.DrawText(dayStr
, x
, y
+ 1);
1149 if ( !isSel
&& attr
&& attr
->HasBorder() )
1152 if ( attr
->HasBorderColour() )
1154 colBorder
= attr
->GetBorderColour();
1158 colBorder
= m_foregroundColour
;
1161 wxPen
pen(colBorder
, 1, wxSOLID
);
1163 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1165 switch ( attr
->GetBorder() )
1167 case wxCAL_BORDER_SQUARE
:
1168 dc
.DrawRectangle(x
- 2, y
,
1169 width
+ 4, m_heightRow
);
1172 case wxCAL_BORDER_ROUND
:
1173 dc
.DrawEllipse(x
- 2, y
,
1174 width
+ 4, m_heightRow
);
1178 wxFAIL_MSG(_T("unknown border type"));
1182 if ( changedColours
)
1184 dc
.SetTextForeground(m_foregroundColour
);
1185 dc
.SetTextBackground(m_backgroundColour
);
1193 //else: just don't draw it
1195 date
+= wxDateSpan::Day();
1199 // Greying out out-of-range background
1200 bool showSurrounding
= (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS
) != 0;
1202 date
= ( showSurrounding
) ? GetStartDate() : wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear());
1203 if ( !IsDateInRange(date
) )
1205 wxDateTime firstOOR
= GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1207 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1208 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1210 HighlightRange(&dc
, date
, firstOOR
, wxTRANSPARENT_PEN
, &oorbrush
);
1213 date
= ( showSurrounding
) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear());
1214 if ( !IsDateInRange(date
) )
1216 wxDateTime firstOOR
= GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1218 wxBrush oorbrush
= *wxLIGHT_GREY_BRUSH
;
1219 oorbrush
.SetStyle(wxFDIAGONAL_HATCH
);
1221 HighlightRange(&dc
, firstOOR
, date
, wxTRANSPARENT_PEN
, &oorbrush
);
1225 wxLogDebug("+++ finished painting");
1229 void wxCalendarCtrl::RefreshDate(const wxDateTime
& date
)
1235 // always refresh the whole row at once because our OnPaint() will draw
1236 // the whole row anyhow - and this allows the small optimisation in
1237 // OnClick() below to work
1240 rect
.y
= (m_heightRow
* GetWeek(date
)) + m_rowOffset
;
1242 rect
.width
= 7*m_widthCol
;
1243 rect
.height
= m_heightRow
;
1246 // VZ: for some reason, the selected date seems to occupy more space under
1247 // MSW - this is probably some bug in the font size calculations, but I
1248 // don't know where exactly. This fix is ugly and leads to more
1249 // refreshes than really needed, but without it the selected days
1250 // leaves even more ugly underscores on screen.
1255 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
1258 rect
.x
+ rect
.width
, rect
.y
+ rect
.height
);
1261 Refresh(TRUE
, &rect
);
1264 void wxCalendarCtrl::HighlightRange(wxPaintDC
* pDC
, const wxDateTime
& fromdate
, const wxDateTime
& todate
, wxPen
* pPen
, wxBrush
* pBrush
)
1266 // Highlights the given range using pen and brush
1267 // Does nothing if todate < fromdate
1271 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate
.Format("%d %m %Y"), todate
.Format("%d %m %Y"));
1274 if ( todate
>= fromdate
)
1281 // implicit: both dates must be currently shown - checked by GetDateCoord
1282 if ( GetDateCoord(fromdate
, &fd
, &fw
) && GetDateCoord(todate
, &td
, &tw
) )
1285 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd
, fw
, td
, tw
);
1287 if ( ( (tw
- fw
) == 1 ) && ( td
< fd
) )
1289 // special case: interval 7 days or less not in same week
1290 // split in two seperate intervals
1291 wxDateTime tfd
= fromdate
+ wxDateSpan::Days(7-fd
);
1292 wxDateTime ftd
= tfd
+ wxDateSpan::Day();
1294 wxLogDebug("Highlight: Seperate segments");
1297 HighlightRange(pDC
, fromdate
, tfd
, pPen
, pBrush
);
1298 HighlightRange(pDC
, ftd
, todate
, pPen
, pBrush
);
1303 wxPoint corners
[8]; // potentially 8 corners in polygon
1307 // simple case: same week
1309 corners
[0] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
);
1310 corners
[1] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1 ) * m_heightRow
) + m_rowOffset
);
1311 corners
[2] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
);
1312 corners
[3] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
);
1317 // "complex" polygon
1318 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1322 corners
[cidx
] = wxPoint((fd
- 1) * m_widthCol
, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1323 corners
[cidx
] = wxPoint(0, ((fw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1326 corners
[cidx
] = wxPoint(0, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1327 corners
[cidx
] = wxPoint(td
* m_widthCol
, ((tw
+ 1) * m_heightRow
) + m_rowOffset
); cidx
++;
1331 corners
[cidx
] = wxPoint(td
* m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1332 corners
[cidx
] = wxPoint(7 * m_widthCol
, (tw
* m_heightRow
) + m_rowOffset
); cidx
++;
1335 corners
[cidx
] = wxPoint(7 * m_widthCol
, (fw
* m_heightRow
) + m_rowOffset
); cidx
++;
1341 pDC
->SetBrush(*pBrush
);
1343 pDC
->DrawPolygon(numpoints
, corners
);
1349 wxLogDebug("--- HighlightRange ---");
1353 bool wxCalendarCtrl::GetDateCoord(const wxDateTime
& date
, int *day
, int *week
) const
1358 wxLogDebug("+++ GetDateCoord: (%s) +++", date
.Format("%d %m %Y"));
1361 if ( IsDateShown(date
) )
1363 bool startOnMonday
= ( GetWindowStyle() & wxCAL_MONDAY_FIRST
) != 0;
1366 *day
= date
.GetWeekDay();
1368 if ( *day
== 0 ) // sunday
1370 *day
= ( startOnMonday
) ? 7 : 1;
1374 day
+= ( startOnMonday
) ? 0 : 1;
1377 int targetmonth
= date
.GetMonth() + (12 * date
.GetYear());
1378 int thismonth
= m_date
.GetMonth() + (12 * m_date
.GetYear());
1381 if ( targetmonth
== thismonth
)
1383 *week
= GetWeek(date
);
1387 if ( targetmonth
< thismonth
)
1389 *week
= 1; // trivial
1391 else // targetmonth > thismonth
1397 // get the datecoord of the last day in the month currently shown
1399 wxLogDebug(" +++ LDOM +++");
1401 GetDateCoord(ldcm
.SetToLastMonthDay(m_date
.GetMonth(), m_date
.GetYear()), &lastday
, &lastweek
);
1403 wxLogDebug(" --- LDOM ---");
1406 wxTimeSpan span
= date
- ldcm
;
1408 int daysfromlast
= span
.GetDays();
1410 wxLogDebug("daysfromlast: %i", daysfromlast
);
1412 if ( daysfromlast
+ lastday
> 7 ) // past week boundary
1414 int wholeweeks
= (daysfromlast
/ 7);
1415 *week
= wholeweeks
+ lastweek
;
1416 if ( (daysfromlast
- (7 * wholeweeks
) + lastday
) > 7 )
1436 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date
.Format("%d %m %Y"), *day
, *week
);
1442 // ----------------------------------------------------------------------------
1444 // ----------------------------------------------------------------------------
1446 void wxCalendarCtrl::OnDClick(wxMouseEvent
& event
)
1448 if ( HitTest(event
.GetPosition()) != wxCAL_HITTEST_DAY
)
1454 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1458 void wxCalendarCtrl::OnClick(wxMouseEvent
& event
)
1461 wxDateTime::WeekDay wday
;
1462 switch ( HitTest(event
.GetPosition(), &date
, &wday
) )
1464 case wxCAL_HITTEST_DAY
:
1465 if ( IsDateInRange(date
) )
1469 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED
,
1470 wxEVT_CALENDAR_SEL_CHANGED
);
1474 case wxCAL_HITTEST_HEADER
:
1476 wxCalendarEvent
event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED
);
1477 event
.m_wday
= wday
;
1478 (void)GetEventHandler()->ProcessEvent(event
);
1482 case wxCAL_HITTEST_DECMONTH
:
1483 case wxCAL_HITTEST_INCMONTH
:
1484 case wxCAL_HITTEST_SURROUNDING_WEEK
:
1485 SetDateAndNotify(date
); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1489 wxFAIL_MSG(_T("unknown hittest code"));
1492 case wxCAL_HITTEST_NOWHERE
:
1498 wxCalendarHitTestResult
wxCalendarCtrl::HitTest(const wxPoint
& pos
,
1500 wxDateTime::WeekDay
*wd
)
1506 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1507 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION
) )
1511 // we need to find out if the hit is on left arrow, on month or on right arrow
1513 if ( wxRegion(m_leftArrowRect
).Contains(pos
) == wxInRegion
)
1517 if ( IsDateInRange(m_date
- wxDateSpan::Month()) )
1519 *date
= m_date
- wxDateSpan::Month();
1523 *date
= GetLowerDateLimit();
1527 return wxCAL_HITTEST_DECMONTH
;
1530 if ( wxRegion(m_rightArrowRect
).Contains(pos
) == wxInRegion
)
1534 if ( IsDateInRange(m_date
+ wxDateSpan::Month()) )
1536 *date
= m_date
+ wxDateSpan::Month();
1540 *date
= GetUpperDateLimit();
1544 return wxCAL_HITTEST_INCMONTH
;
1549 ///////////////////////////////////////////////////////////////////////////////////////////////////////
1551 int wday
= pos
.x
/ m_widthCol
;
1552 // if ( y < m_heightRow )
1553 if ( y
< (m_heightRow
+ m_rowOffset
) )
1555 if ( y
> m_rowOffset
)
1559 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST
)
1561 wday
= wday
== 6 ? 0 : wday
+ 1;
1564 *wd
= (wxDateTime::WeekDay
)wday
;
1567 return wxCAL_HITTEST_HEADER
;
1571 return wxCAL_HITTEST_NOWHERE
;
1575 // int week = (y - m_heightRow) / m_heightRow;
1576 int week
= (y
- (m_heightRow
+ m_rowOffset
)) / m_heightRow
;
1577 if ( week
>= 6 || wday
>= 7 )
1579 return wxCAL_HITTEST_NOWHERE
;
1582 wxDateTime dt
= GetStartDate() + wxDateSpan::Days(7*week
+ wday
);
1584 if ( IsDateShown(dt
) )
1589 if ( dt
.GetMonth() == m_date
.GetMonth() )
1592 return wxCAL_HITTEST_DAY
;
1596 return wxCAL_HITTEST_SURROUNDING_WEEK
;
1601 return wxCAL_HITTEST_NOWHERE
;
1605 // ----------------------------------------------------------------------------
1606 // subcontrols events handling
1607 // ----------------------------------------------------------------------------
1609 void wxCalendarCtrl::OnMonthChange(wxCommandEvent
& event
)
1611 wxDateTime::Tm tm
= m_date
.GetTm();
1613 wxDateTime::Month mon
= (wxDateTime::Month
)event
.GetInt();
1614 if ( tm
.mday
> wxDateTime::GetNumberOfDays(mon
, tm
.year
) )
1616 tm
.mday
= wxDateTime::GetNumberOfDays(mon
, tm
.year
);
1619 wxDateTime target
= wxDateTime(tm
.mday
, mon
, tm
.year
);
1621 ChangeMonth(&target
);
1622 SetDateAndNotify(target
);
1625 void wxCalendarCtrl::OnYearChange(wxCommandEvent
& event
)
1627 int year
= (int)event
.GetInt();
1628 if ( year
== INT_MIN
)
1630 // invalid year in the spin control, ignore it
1634 wxDateTime::Tm tm
= m_date
.GetTm();
1636 if ( tm
.mday
> wxDateTime::GetNumberOfDays(tm
.mon
, year
) )
1638 tm
.mday
= wxDateTime::GetNumberOfDays(tm
.mon
, year
);
1641 wxDateTime target
= wxDateTime(tm
.mday
, tm
.mon
, year
);
1643 if ( ChangeYear(&target
) )
1645 SetDateAndNotify(target
);
1649 // In this case we don't want to change the date. That would put us
1650 // inside the same year but a strange number of months forward/back..
1651 m_spinYear
->SetValue(target
.GetYear());
1655 // ----------------------------------------------------------------------------
1656 // keyboard interface
1657 // ----------------------------------------------------------------------------
1659 void wxCalendarCtrl::OnChar(wxKeyEvent
& event
)
1662 switch ( event
.GetKeyCode() )
1666 target
= m_date
+ wxDateSpan::Year();
1667 if ( ChangeYear(&target
) )
1669 SetDateAndNotify(target
);
1675 target
= m_date
- wxDateSpan::Year();
1676 if ( ChangeYear(&target
) )
1678 SetDateAndNotify(target
);
1683 target
= m_date
- wxDateSpan::Month();
1684 ChangeMonth(&target
);
1685 SetDateAndNotify(target
); // always
1689 target
= m_date
+ wxDateSpan::Month();
1690 ChangeMonth(&target
);
1691 SetDateAndNotify(target
); // always
1695 if ( event
.ControlDown() )
1697 target
= wxDateTime(m_date
).SetToNextWeekDay(
1698 GetWindowStyle() & wxCAL_MONDAY_FIRST
1699 ? wxDateTime::Sun
: wxDateTime::Sat
);
1700 if ( !IsDateInRange(target
) )
1702 target
= GetUpperDateLimit();
1704 SetDateAndNotify(target
);
1707 SetDateAndNotify(m_date
+ wxDateSpan::Day());
1711 if ( event
.ControlDown() )
1713 target
= wxDateTime(m_date
).SetToPrevWeekDay(
1714 GetWindowStyle() & wxCAL_MONDAY_FIRST
1715 ? wxDateTime::Mon
: wxDateTime::Sun
);
1716 if ( !IsDateInRange(target
) )
1718 target
= GetLowerDateLimit();
1720 SetDateAndNotify(target
);
1723 SetDateAndNotify(m_date
- wxDateSpan::Day());
1727 SetDateAndNotify(m_date
- wxDateSpan::Week());
1731 SetDateAndNotify(m_date
+ wxDateSpan::Week());
1735 if ( event
.ControlDown() )
1736 SetDateAndNotify(wxDateTime::Today());
1738 SetDateAndNotify(wxDateTime(1, m_date
.GetMonth(), m_date
.GetYear()));
1742 SetDateAndNotify(wxDateTime(m_date
).SetToLastMonthDay());
1746 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED
);
1754 // ----------------------------------------------------------------------------
1755 // holidays handling
1756 // ----------------------------------------------------------------------------
1758 void wxCalendarCtrl::EnableHolidayDisplay(bool display
)
1760 long style
= GetWindowStyle();
1762 style
|= wxCAL_SHOW_HOLIDAYS
;
1764 style
&= ~wxCAL_SHOW_HOLIDAYS
;
1766 SetWindowStyle(style
);
1771 ResetHolidayAttrs();
1776 void wxCalendarCtrl::SetHolidayAttrs()
1778 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS
)
1780 ResetHolidayAttrs();
1782 wxDateTime::Tm tm
= m_date
.GetTm();
1783 wxDateTime
dtStart(1, tm
.mon
, tm
.year
),
1784 dtEnd
= dtStart
.GetLastMonthDay();
1786 wxDateTimeArray hol
;
1787 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart
, dtEnd
, hol
);
1789 size_t count
= hol
.GetCount();
1790 for ( size_t n
= 0; n
< count
; n
++ )
1792 SetHoliday(hol
[n
].GetDay());
1797 void wxCalendarCtrl::SetHoliday(size_t day
)
1799 wxCHECK_RET( day
> 0 && day
< 32, _T("invalid day in SetHoliday") );
1801 wxCalendarDateAttr
*attr
= GetAttr(day
);
1804 attr
= new wxCalendarDateAttr
;
1807 attr
->SetHoliday(TRUE
);
1809 // can't use SetAttr() because it would delete this pointer
1810 m_attrs
[day
- 1] = attr
;
1813 void wxCalendarCtrl::ResetHolidayAttrs()
1815 for ( size_t day
= 0; day
< 31; day
++ )
1819 m_attrs
[day
]->SetHoliday(FALSE
);
1824 // ----------------------------------------------------------------------------
1826 // ----------------------------------------------------------------------------
1828 void wxCalendarEvent::Init()
1830 m_wday
= wxDateTime::Inv_WeekDay
;
1833 wxCalendarEvent::wxCalendarEvent(wxCalendarCtrl
*cal
, wxEventType type
)
1834 : wxCommandEvent(type
, cal
->GetId())
1836 m_date
= cal
->GetDate();
1837 SetEventObject(cal
);
1840 #endif // wxUSE_CALENDARCTRL