]> git.saurik.com Git - wxWidgets.git/blame - src/generic/calctrl.cpp
Fixed bug [ 754596 ] wxUSE_CONSTRAINTS 0 breaks AutoLayout() with sizers
[wxWidgets.git] / src / generic / calctrl.cpp
CommitLineData
2ef31e80
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: generic/calctrl.cpp
3// Purpose: implementation fo the generic wxCalendarCtrl
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 29.12.99
7// RCS-ID: $Id$
8// Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
6aa89a22 9// Licence: wxWindows licence
2ef31e80
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
2ef31e80
VZ
21 #pragma implementation "calctrl.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#ifndef WX_PRECOMP
9d9b7755
VZ
32 #include "wx/dcclient.h"
33 #include "wx/settings.h"
34 #include "wx/brush.h"
4f6aed9c 35 #include "wx/combobox.h"
bc385ba9 36 #include "wx/stattext.h"
25f430fc 37 #include "wx/textctrl.h"
2ef31e80
VZ
38#endif //WX_PRECOMP
39
1e6feb95 40#if wxUSE_CALENDARCTRL
2fa7c206 41
f0d5e7a2
VZ
42#include "wx/spinctrl.h"
43
9d9b7755 44#include "wx/calctrl.h"
2ef31e80 45
882a8f40
VZ
46#define DEBUG_PAINT 0
47
48// ----------------------------------------------------------------------------
49// private classes
50// ----------------------------------------------------------------------------
51
52class wxMonthComboBox : public wxComboBox
53{
54public:
55 wxMonthComboBox(wxCalendarCtrl *cal);
56
57 void OnMonthChange(wxCommandEvent& event) { m_cal->OnMonthChange(event); }
58
59private:
60 wxCalendarCtrl *m_cal;
61
62 DECLARE_EVENT_TABLE()
22f3361e 63 DECLARE_NO_COPY_CLASS(wxMonthComboBox)
882a8f40
VZ
64};
65
66class wxYearSpinCtrl : public wxSpinCtrl
67{
68public:
69 wxYearSpinCtrl(wxCalendarCtrl *cal);
70
605dfd91
JS
71 void OnYearTextChange(wxCommandEvent& event)
72 {
73 m_cal->SetUserChangedYear();
74 m_cal->OnYearChange(event);
75 }
882a8f40
VZ
76 void OnYearChange(wxSpinEvent& event) { m_cal->OnYearChange(event); }
77
78private:
79 wxCalendarCtrl *m_cal;
80
81 DECLARE_EVENT_TABLE()
22f3361e 82 DECLARE_NO_COPY_CLASS(wxYearSpinCtrl)
882a8f40
VZ
83};
84
2ef31e80
VZ
85// ----------------------------------------------------------------------------
86// wxWin macros
87// ----------------------------------------------------------------------------
88
89BEGIN_EVENT_TABLE(wxCalendarCtrl, wxControl)
90 EVT_PAINT(wxCalendarCtrl::OnPaint)
91
9d9b7755
VZ
92 EVT_CHAR(wxCalendarCtrl::OnChar)
93
2ef31e80 94 EVT_LEFT_DOWN(wxCalendarCtrl::OnClick)
0185cd09 95 EVT_LEFT_DCLICK(wxCalendarCtrl::OnDClick)
882a8f40
VZ
96END_EVENT_TABLE()
97
98BEGIN_EVENT_TABLE(wxMonthComboBox, wxComboBox)
99 EVT_COMBOBOX(-1, wxMonthComboBox::OnMonthChange)
100END_EVENT_TABLE()
9d9b7755 101
882a8f40 102BEGIN_EVENT_TABLE(wxYearSpinCtrl, wxSpinCtrl)
f0d5e7a2 103 EVT_TEXT(-1, wxYearSpinCtrl::OnYearTextChange)
882a8f40 104 EVT_SPINCTRL(-1, wxYearSpinCtrl::OnYearChange)
2ef31e80
VZ
105END_EVENT_TABLE()
106
b0a877ec 107#if wxUSE_EXTENDED_RTTI
73c36334
JS
108WX_DEFINE_FLAGS( wxCalendarCtrlStyle )
109
3ff066a4 110wxBEGIN_FLAGS( wxCalendarCtrlStyle )
73c36334
JS
111 // new style border flags, we put them first to
112 // use them for streaming out
3ff066a4
SC
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)
73c36334
JS
119
120 // old style border flags
3ff066a4
SC
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)
73c36334
JS
127
128 // standard window styles
3ff066a4
SC
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)
137
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)
145
146wxEND_FLAGS( wxCalendarCtrlStyle )
73c36334 147
b0a877ec
SC
148IMPLEMENT_DYNAMIC_CLASS_XTI(wxCalendarCtrl, wxControl,"wx/calctrl.h")
149
3ff066a4
SC
150wxBEGIN_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
155wxEND_PROPERTIES_TABLE()
b0a877ec 156
3ff066a4
SC
157wxBEGIN_HANDLERS_TABLE(wxCalendarCtrl)
158wxEND_HANDLERS_TABLE()
b0a877ec 159
3ff066a4 160wxCONSTRUCTOR_6( wxCalendarCtrl , wxWindow* , Parent , wxWindowID , Id , wxDateTime , Date , wxPoint , Position , wxSize , Size , long , WindowStyle )
b0a877ec 161#else
2ef31e80 162IMPLEMENT_DYNAMIC_CLASS(wxCalendarCtrl, wxControl)
b0a877ec 163#endif
f6bcfd97 164IMPLEMENT_DYNAMIC_CLASS(wxCalendarEvent, wxCommandEvent)
2ef31e80 165
2e4df4bf
VZ
166// ----------------------------------------------------------------------------
167// events
168// ----------------------------------------------------------------------------
169
170DEFINE_EVENT_TYPE(wxEVT_CALENDAR_SEL_CHANGED)
171DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DAY_CHANGED)
172DEFINE_EVENT_TYPE(wxEVT_CALENDAR_MONTH_CHANGED)
173DEFINE_EVENT_TYPE(wxEVT_CALENDAR_YEAR_CHANGED)
174DEFINE_EVENT_TYPE(wxEVT_CALENDAR_DOUBLECLICKED)
175DEFINE_EVENT_TYPE(wxEVT_CALENDAR_WEEKDAY_CLICKED)
176
2ef31e80
VZ
177// ============================================================================
178// implementation
179// ============================================================================
180
882a8f40
VZ
181// ----------------------------------------------------------------------------
182// wxMonthComboBox and wxYearSpinCtrl
183// ----------------------------------------------------------------------------
184
185wxMonthComboBox::wxMonthComboBox(wxCalendarCtrl *cal)
186 : wxComboBox(cal->GetParent(), -1,
187 wxEmptyString,
188 wxDefaultPosition,
189 wxDefaultSize,
190 0, NULL,
fdda2df6 191 wxCB_READONLY | wxCLIP_SIBLINGS)
882a8f40
VZ
192{
193 m_cal = cal;
194
195 wxDateTime::Month m;
196 for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) )
197 {
198 Append(wxDateTime::GetMonthName(m));
199 }
200
201 SetSelection(m_cal->GetDate().GetMonth());
f6bcfd97 202 SetSize(-1, -1, -1, -1, wxSIZE_AUTO_WIDTH|wxSIZE_AUTO_HEIGHT);
882a8f40
VZ
203}
204
205wxYearSpinCtrl::wxYearSpinCtrl(wxCalendarCtrl *cal)
206 : wxSpinCtrl(cal->GetParent(), -1,
207 cal->GetDate().Format(_T("%Y")),
208 wxDefaultPosition,
209 wxDefaultSize,
fdda2df6 210 wxSP_ARROW_KEYS | wxCLIP_SIBLINGS,
882a8f40 211 -4300, 10000, cal->GetDate().GetYear())
95bcc40c 212
882a8f40
VZ
213{
214 m_cal = cal;
215}
216
2ef31e80
VZ
217// ----------------------------------------------------------------------------
218// wxCalendarCtrl
219// ----------------------------------------------------------------------------
220
2b5f62a0
VZ
221wxCalendarCtrl::wxCalendarCtrl(wxWindow *parent,
222 wxWindowID id,
223 const wxDateTime& date,
224 const wxPoint& pos,
225 const wxSize& size,
226 long style,
227 const wxString& name)
228{
229 Init();
230
231 (void)Create(parent, id, date, pos, size, style, name);
232}
233
2ef31e80
VZ
234void wxCalendarCtrl::Init()
235{
236 m_comboMonth = NULL;
237 m_spinYear = NULL;
1882f416
JS
238 m_staticYear = NULL;
239 m_staticMonth = NULL;
2ef31e80 240
f0d5e7a2
VZ
241 m_userChangedYear = FALSE;
242
2ef31e80
VZ
243 m_widthCol =
244 m_heightRow = 0;
9d9b7755
VZ
245
246 wxDateTime::WeekDay wd;
247 for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) )
248 {
249 m_weekdays[wd] = wxDateTime::GetWeekDayName(wd, wxDateTime::Name_Abbr);
250 }
3965571c 251
4f6aed9c
VZ
252 for ( size_t n = 0; n < WXSIZEOF(m_attrs); n++ )
253 {
254 m_attrs[n] = NULL;
255 }
256
7516ed26
VZ
257 m_colHighlightFg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
258 m_colHighlightBg = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
4f6aed9c
VZ
259
260 m_colHolidayFg = *wxRED;
261 // don't set m_colHolidayBg - by default, same as our bg colour
262
263 m_colHeaderFg = *wxBLUE;
264 m_colHeaderBg = *wxLIGHT_GREY;
2ef31e80
VZ
265}
266
4965c3d7
VZ
267bool wxCalendarCtrl::Create(wxWindow *parent,
268 wxWindowID id,
2ef31e80 269 const wxDateTime& date,
4965c3d7 270 const wxPoint& pos,
2ef31e80
VZ
271 const wxSize& size,
272 long style,
4965c3d7 273 const wxString& name)
2ef31e80 274{
4965c3d7 275 if ( !wxControl::Create(parent, id, pos, size,
fdda2df6
VZ
276 style | wxCLIP_CHILDREN | wxWANTS_CHARS,
277 wxDefaultValidator, name) )
4965c3d7
VZ
278 {
279 return FALSE;
280 }
281
bc385ba9
VZ
282 // needed to get the arrow keys normally used for the dialog navigation
283 SetWindowStyle(style | wxWANTS_CHARS);
2ef31e80 284
882a8f40 285 m_date = date.IsValid() ? date : wxDateTime::Today();
9d9b7755 286
37df1f33
VZ
287 m_lowdate = wxDefaultDateTime;
288 m_highdate = wxDefaultDateTime;
bc385ba9 289
bb61a983 290 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
37df1f33
VZ
291 {
292 m_spinYear = new wxYearSpinCtrl(this);
293 m_staticYear = new wxStaticText(GetParent(), -1, m_date.Format(_T("%Y")),
294 wxDefaultPosition, wxDefaultSize,
295 wxALIGN_CENTRE);
296
297 m_comboMonth = new wxMonthComboBox(this);
298 m_staticMonth = new wxStaticText(GetParent(), -1, m_date.Format(_T("%B")),
299 wxDefaultPosition, wxDefaultSize,
300 wxALIGN_CENTRE);
301 }
bc385ba9
VZ
302
303 ShowCurrentControls();
9d9b7755 304
2ef31e80
VZ
305 wxSize sizeReal;
306 if ( size.x == -1 || size.y == -1 )
307 {
308 sizeReal = DoGetBestSize();
309 if ( size.x != -1 )
310 sizeReal.x = size.x;
311 if ( size.y != -1 )
312 sizeReal.y = size.y;
313 }
314 else
315 {
316 sizeReal = size;
317 }
318
bb61a983
VZ
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
321 // above it
322 SetSize(pos.x, pos.y, sizeReal.x, sizeReal.y);
2ef31e80
VZ
323
324 SetBackgroundColour(*wxWHITE);
9d9b7755 325 SetFont(*wxSWISS_FONT);
2ef31e80 326
4f6aed9c
VZ
327 SetHolidayAttrs();
328
2ef31e80
VZ
329 return TRUE;
330}
331
882a8f40
VZ
332wxCalendarCtrl::~wxCalendarCtrl()
333{
4f6aed9c
VZ
334 for ( size_t n = 0; n < WXSIZEOF(m_attrs); n++ )
335 {
336 delete m_attrs[n];
337 }
882a8f40
VZ
338}
339
340// ----------------------------------------------------------------------------
341// forward wxWin functions to subcontrols
342// ----------------------------------------------------------------------------
343
b70462f4
MB
344bool wxCalendarCtrl::Destroy()
345{
f0d5e7a2
VZ
346 if ( m_staticYear )
347 m_staticYear->Destroy();
348 if ( m_spinYear )
349 m_spinYear->Destroy();
350 if ( m_comboMonth )
351 m_comboMonth->Destroy();
352 if ( m_staticMonth )
353 m_staticMonth->Destroy();
354
355 m_staticYear = NULL;
356 m_spinYear = NULL;
357 m_comboMonth = NULL;
358 m_staticMonth = NULL;
b70462f4
MB
359
360 return wxControl::Destroy();
361}
362
882a8f40
VZ
363bool wxCalendarCtrl::Show(bool show)
364{
365 if ( !wxControl::Show(show) )
366 {
367 return FALSE;
368 }
369
37df1f33
VZ
370 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
371 {
372 if ( GetMonthControl() )
373 {
374 GetMonthControl()->Show(show);
375 GetYearControl()->Show(show);
376 }
377 }
882a8f40
VZ
378
379 return TRUE;
380}
381
382bool wxCalendarCtrl::Enable(bool enable)
383{
384 if ( !wxControl::Enable(enable) )
385 {
386 return FALSE;
387 }
388
37df1f33
VZ
389 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
390 {
391 GetMonthControl()->Enable(enable);
392 GetYearControl()->Enable(enable);
393 }
882a8f40
VZ
394
395 return TRUE;
396}
397
bc385ba9
VZ
398// ----------------------------------------------------------------------------
399// enable/disable month/year controls
400// ----------------------------------------------------------------------------
401
402void wxCalendarCtrl::ShowCurrentControls()
403{
bb61a983 404 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
bc385ba9 405 {
37df1f33 406 if ( AllowMonthChange() )
bc385ba9 407 {
37df1f33
VZ
408 m_comboMonth->Show();
409 m_staticMonth->Hide();
410
411 if ( AllowYearChange() )
412 {
413 m_spinYear->Show();
414 m_staticYear->Hide();
bc385ba9 415
37df1f33
VZ
416 // skip the rest
417 return;
418 }
419 }
420 else
421 {
422 m_comboMonth->Hide();
423 m_staticMonth->Show();
bc385ba9 424 }
bc385ba9 425
37df1f33
VZ
426 // year change not allowed here
427 m_spinYear->Hide();
428 m_staticYear->Show();
429 }
bc385ba9
VZ
430}
431
432wxControl *wxCalendarCtrl::GetMonthControl() const
433{
380d9d62 434 return AllowMonthChange() ? (wxControl *)m_comboMonth : (wxControl *)m_staticMonth;
bc385ba9
VZ
435}
436
437wxControl *wxCalendarCtrl::GetYearControl() const
438{
380d9d62 439 return AllowYearChange() ? (wxControl *)m_spinYear : (wxControl *)m_staticYear;
bc385ba9
VZ
440}
441
442void wxCalendarCtrl::EnableYearChange(bool enable)
443{
444 if ( enable != AllowYearChange() )
445 {
446 long style = GetWindowStyle();
447 if ( enable )
448 style &= ~wxCAL_NO_YEAR_CHANGE;
449 else
450 style |= wxCAL_NO_YEAR_CHANGE;
451 SetWindowStyle(style);
452
453 ShowCurrentControls();
37df1f33
VZ
454 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION )
455 {
456 Refresh();
457 }
bc385ba9
VZ
458 }
459}
460
461void wxCalendarCtrl::EnableMonthChange(bool enable)
462{
463 if ( enable != AllowMonthChange() )
464 {
465 long style = GetWindowStyle();
466 if ( enable )
467 style &= ~wxCAL_NO_MONTH_CHANGE;
468 else
469 style |= wxCAL_NO_MONTH_CHANGE;
470 SetWindowStyle(style);
1bcf0c7d 471
bc385ba9 472 ShowCurrentControls();
37df1f33
VZ
473 if ( GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION )
474 {
475 Refresh();
476 }
bc385ba9
VZ
477 }
478}
479
9d9b7755
VZ
480// ----------------------------------------------------------------------------
481// changing date
482// ----------------------------------------------------------------------------
483
37df1f33 484bool wxCalendarCtrl::SetDate(const wxDateTime& date)
9d9b7755 485{
f0d5e7a2 486 bool retval = TRUE;
37df1f33 487
bc385ba9
VZ
488 bool sameMonth = m_date.GetMonth() == date.GetMonth(),
489 sameYear = m_date.GetYear() == date.GetYear();
490
37df1f33 491 if ( IsDateInRange(date) )
9d9b7755 492 {
37df1f33 493 if ( sameMonth && sameYear )
bc385ba9 494 {
37df1f33 495 // just change the day
37df1f33 496 ChangeDay(date);
bc385ba9 497 }
37df1f33
VZ
498 else
499 {
f0d5e7a2 500 if ( AllowMonthChange() && (AllowYearChange() || sameYear) )
37df1f33 501 {
f0d5e7a2
VZ
502 // change everything
503 m_date = date;
bc385ba9 504
f0d5e7a2 505 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
37df1f33 506 {
f0d5e7a2
VZ
507 // update the controls
508 m_comboMonth->SetSelection(m_date.GetMonth());
509
510 if ( AllowYearChange() )
511 {
512 if ( !m_userChangedYear )
513 m_spinYear->SetValue(m_date.Format(_T("%Y")));
f0d5e7a2 514 }
37df1f33 515 }
9d9b7755 516
f0d5e7a2
VZ
517 // as the month changed, holidays did too
518 SetHolidayAttrs();
0de868d9 519
f0d5e7a2
VZ
520 // update the calendar
521 Refresh();
522 }
523 else
524 {
525 // forbidden
526 retval = FALSE;
527 }
37df1f33 528 }
9d9b7755 529 }
37df1f33 530
605dfd91
JS
531 m_userChangedYear = FALSE;
532
37df1f33 533 return retval;
9d9b7755
VZ
534}
535
536void wxCalendarCtrl::ChangeDay(const wxDateTime& date)
537{
538 if ( m_date != date )
539 {
540 // we need to refresh the row containing the old date and the one
541 // containing the new one
542 wxDateTime dateOld = m_date;
543 m_date = date;
544
545 RefreshDate(dateOld);
546
547 // if the date is in the same row, it was already drawn correctly
548 if ( GetWeek(m_date) != GetWeek(dateOld) )
549 {
550 RefreshDate(m_date);
551 }
552 }
553}
554
555void wxCalendarCtrl::SetDateAndNotify(const wxDateTime& date)
556{
557 wxDateTime::Tm tm1 = m_date.GetTm(),
558 tm2 = date.GetTm();
559
560 wxEventType type;
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;
567 else
568 return;
569
37df1f33
VZ
570 if ( SetDate(date) )
571 {
572 GenerateEvents(type, wxEVT_CALENDAR_SEL_CHANGED);
573 }
574}
575
576// ----------------------------------------------------------------------------
577// date range
578// ----------------------------------------------------------------------------
579
580bool wxCalendarCtrl::SetLowerDateLimit(const wxDateTime& date /* = wxDefaultDateTime */)
581{
1bcf0c7d 582 bool retval = TRUE;
37df1f33 583
1bcf0c7d 584 if ( !(date.IsValid()) || ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : TRUE ) )
37df1f33
VZ
585 {
586 m_lowdate = date;
587 }
588 else
589 {
1bcf0c7d 590 retval = FALSE;
37df1f33 591 }
9d9b7755 592
37df1f33
VZ
593 return retval;
594}
595
596bool wxCalendarCtrl::SetUpperDateLimit(const wxDateTime& date /* = wxDefaultDateTime */)
597{
1bcf0c7d 598 bool retval = TRUE;
37df1f33 599
1bcf0c7d 600 if ( !(date.IsValid()) || ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : TRUE ) )
37df1f33
VZ
601 {
602 m_highdate = date;
603 }
604 else
605 {
1bcf0c7d 606 retval = FALSE;
37df1f33
VZ
607 }
608
609 return retval;
610}
611
612bool wxCalendarCtrl::SetDateRange(const wxDateTime& lowerdate /* = wxDefaultDateTime */, const wxDateTime& upperdate /* = wxDefaultDateTime */)
613{
1bcf0c7d 614 bool retval = TRUE;
37df1f33
VZ
615
616 if (
1bcf0c7d
DW
617 ( !( lowerdate.IsValid() ) || ( ( upperdate.IsValid() ) ? ( lowerdate <= upperdate ) : TRUE ) ) &&
618 ( !( upperdate.IsValid() ) || ( ( lowerdate.IsValid() ) ? ( upperdate >= lowerdate ) : TRUE ) ) )
37df1f33
VZ
619 {
620 m_lowdate = lowerdate;
621 m_highdate = upperdate;
622 }
623 else
624 {
1bcf0c7d 625 retval = FALSE;
37df1f33 626 }
1bcf0c7d 627
37df1f33 628 return retval;
9d9b7755
VZ
629}
630
2ef31e80
VZ
631// ----------------------------------------------------------------------------
632// date helpers
633// ----------------------------------------------------------------------------
634
635wxDateTime wxCalendarCtrl::GetStartDate() const
636{
637 wxDateTime::Tm tm = m_date.GetTm();
638
639 wxDateTime date = wxDateTime(1, tm.mon, tm.year);
9d9b7755 640
1a8557b1
VZ
641 // rewind back
642 date.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
643 ? wxDateTime::Mon : wxDateTime::Sun);
644
37df1f33
VZ
645 if ( GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS )
646 {
647 // We want to offset the calendar if we start on the first..
648 if ( date.GetDay() == 1 )
649 {
650 date -= wxDateSpan::Week();
651 }
652 }
653
2ef31e80
VZ
654 return date;
655}
656
657bool wxCalendarCtrl::IsDateShown(const wxDateTime& date) const
658{
37df1f33
VZ
659 if ( !(GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) )
660 {
661 return date.GetMonth() == m_date.GetMonth();
662 }
663 else
664 {
665 return TRUE;
666 }
667}
668
669bool wxCalendarCtrl::IsDateInRange(const wxDateTime& date) const
670{
1bcf0c7d 671 bool retval = TRUE;
37df1f33 672 // Check if the given date is in the range specified
1bcf0c7d
DW
673 retval = ( ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : TRUE )
674 && ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : TRUE ) );
37df1f33
VZ
675 return retval;
676}
677
678bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const
679{
1bcf0c7d 680 bool retval = FALSE;
37df1f33
VZ
681
682 if ( !(IsDateInRange(*target)) )
683 {
684 if ( target->GetYear() < m_date.GetYear() )
685 {
686 if ( target->GetYear() >= GetLowerDateLimit().GetYear() )
687 {
688 *target = GetLowerDateLimit();
1bcf0c7d 689 retval = TRUE;
37df1f33
VZ
690 }
691 else
692 {
693 *target = m_date;
694 }
695 }
696 else
697 {
698 if ( target->GetYear() <= GetUpperDateLimit().GetYear() )
699 {
700 *target = GetUpperDateLimit();
1bcf0c7d 701 retval = TRUE;
37df1f33
VZ
702 }
703 else
704 {
705 *target = m_date;
706 }
707 }
708 }
709 else
710 {
1bcf0c7d 711 retval = TRUE;
37df1f33
VZ
712 }
713
714 return retval;
715}
716
717bool wxCalendarCtrl::ChangeMonth(wxDateTime* target) const
718{
1bcf0c7d 719 bool retval = TRUE;
37df1f33
VZ
720
721 if ( !(IsDateInRange(*target)) )
722 {
1bcf0c7d 723 retval = FALSE;
37df1f33
VZ
724
725 if ( target->GetMonth() < m_date.GetMonth() )
726 {
727 *target = GetLowerDateLimit();
728 }
729 else
730 {
731 *target = GetUpperDateLimit();
732 }
733 }
734
735 return retval;
2ef31e80
VZ
736}
737
9d9b7755
VZ
738size_t wxCalendarCtrl::GetWeek(const wxDateTime& date) const
739{
37df1f33
VZ
740 size_t retval = date.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
741 ? wxDateTime::Monday_First
742 : wxDateTime::Sunday_First);
743
744 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) )
745 {
746 // we need to offset an extra week if we "start" on the 1st of the month
747 wxDateTime::Tm tm = date.GetTm();
748
749 wxDateTime datetest = wxDateTime(1, tm.mon, tm.year);
750
751 // rewind back
752 datetest.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
753 ? wxDateTime::Mon : wxDateTime::Sun);
1bcf0c7d 754
37df1f33
VZ
755 if ( datetest.GetDay() == 1 )
756 {
757 retval += 1;
758 }
759 }
1bcf0c7d 760
37df1f33 761 return retval;
9d9b7755
VZ
762}
763
2ef31e80
VZ
764// ----------------------------------------------------------------------------
765// size management
766// ----------------------------------------------------------------------------
767
9d9b7755
VZ
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
771
bc385ba9
VZ
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
774// the same space
775
9d9b7755
VZ
776// the constants used for the layout
777#define VERT_MARGIN 5 // distance between combo and calendar
81b6ccf1
SC
778#ifdef __WXMAC__
779#define HORZ_MARGIN 5 // spin
780#else
9d9b7755 781#define HORZ_MARGIN 15 // spin
81b6ccf1 782#endif
2ef31e80
VZ
783wxSize wxCalendarCtrl::DoGetBestSize() const
784{
9d9b7755
VZ
785 // calc the size of the calendar
786 ((wxCalendarCtrl *)this)->RecalcGeometry(); // const_cast
787
788 wxCoord width = 7*m_widthCol,
bb61a983 789 height = 7*m_heightRow + m_rowOffset + VERT_MARGIN;
9d9b7755 790
bb61a983 791 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
37df1f33 792 {
bb61a983
VZ
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;
37df1f33
VZ
796 }
797
bb61a983 798 if ( !HasFlag(wxBORDER_NONE) )
bc385ba9
VZ
799 {
800 // the border would clip the last line otherwise
f41cb81e 801 height += 6;
37df1f33 802 width += 4;
bc385ba9
VZ
803 }
804
9d9b7755 805 return wxSize(width, height);
2ef31e80
VZ
806}
807
808void wxCalendarCtrl::DoSetSize(int x, int y,
809 int width, int height,
810 int sizeFlags)
811{
812 wxControl::DoSetSize(x, y, width, height, sizeFlags);
813}
814
815void wxCalendarCtrl::DoMoveWindow(int x, int y, int width, int height)
816{
bb61a983 817 int yDiff;
2ef31e80 818
bb61a983 819 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
37df1f33
VZ
820 {
821 wxSize sizeCombo = m_comboMonth->GetSize();
822 wxSize sizeStatic = m_staticMonth->GetSize();
95bcc40c 823 wxSize sizeSpin = m_spinYear->GetSize();
37df1f33 824 int dy = (sizeCombo.y - sizeStatic.y) / 2;
e910c000
JS
825/*
826In the calender the size of the combobox for the year
827is just defined by a margin from the month combobox to
828the left border. While in wxUniv the year control can't
829show all 4 digits, in wxMsw it show almost twice as
830much. Instead the year should use it's best size and be
831left aligned to the calendar. Just in case the month in
832any language is longer than it has space in the
833calendar it is shortend.This way the year always can
834show the 4 digits.
835
836This patch relies on the fact that a combobox has a
837good best size implementation. This is not the case
838with wxMSW but I don't know why.
839
840Otto Wyss
841*/
842
843#ifdef __WXUNIVERSAL__
95bcc40c
JS
844 if (sizeCombo.x + HORZ_MARGIN - sizeSpin.x > width)
845 {
846 m_comboMonth->SetSize(x, y, width - HORZ_MARGIN - sizeSpin.x, sizeCombo.y);
847 }
848 else
849 {
850 m_comboMonth->Move(x, y);
851 }
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);
e910c000
JS
855#else
856 m_comboMonth->Move(x, y);
857 m_staticMonth->SetSize(x, y + dy, sizeCombo.x, sizeStatic.y);
37df1f33 858
e910c000
JS
859 int xDiff = sizeCombo.x + HORZ_MARGIN;
860
861 m_spinYear->SetSize(x + xDiff, y, width - xDiff, sizeCombo.y);
862 m_staticYear->SetSize(x + xDiff, y + dy, width - xDiff, sizeStatic.y);
863#endif
37df1f33
VZ
864 yDiff = wxMax(sizeSpin.y, sizeCombo.y) + VERT_MARGIN;
865 }
bb61a983
VZ
866 else // no controls on the top
867 {
868 yDiff = 0;
869 }
9d9b7755
VZ
870
871 wxControl::DoMoveWindow(x, y + yDiff, width, height - yDiff);
872}
873
882a8f40
VZ
874void wxCalendarCtrl::DoGetPosition(int *x, int *y) const
875{
876 wxControl::DoGetPosition(x, y);
877
37df1f33 878 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
882a8f40 879 {
37df1f33
VZ
880 // our real top corner is not in this position
881 if ( y )
882 {
883 *y -= GetMonthControl()->GetSize().y + VERT_MARGIN;
884 }
882a8f40
VZ
885 }
886}
887
888void wxCalendarCtrl::DoGetSize(int *width, int *height) const
889{
890 wxControl::DoGetSize(width, height);
891
37df1f33 892 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
882a8f40 893 {
37df1f33 894 // our real height is bigger
5b3610da 895 if ( height && GetMonthControl())
37df1f33
VZ
896 {
897 *height += GetMonthControl()->GetSize().y + VERT_MARGIN;
898 }
882a8f40
VZ
899 }
900}
901
9d9b7755 902void wxCalendarCtrl::RecalcGeometry()
2ef31e80 903{
9d9b7755
VZ
904 if ( m_widthCol != 0 )
905 return;
2ef31e80 906
9d9b7755 907 wxClientDC dc(this);
3965571c 908
9d9b7755 909 dc.SetFont(m_font);
3965571c 910
2ef31e80
VZ
911 // determine the column width (we assume that the weekday names are always
912 // wider (in any language) than the numbers)
913 m_widthCol = 0;
9d9b7755 914 wxDateTime::WeekDay wd;
2ef31e80
VZ
915 for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) )
916 {
2ef31e80 917 wxCoord width;
9d9b7755 918 dc.GetTextExtent(m_weekdays[wd], &width, &m_heightRow);
2ef31e80
VZ
919 if ( width > m_widthCol )
920 {
921 m_widthCol = width;
922 }
923 }
3965571c 924
2ef31e80
VZ
925 // leave some margins
926 m_widthCol += 2;
927 m_heightRow += 2;
37df1f33
VZ
928
929 m_rowOffset = (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ? m_heightRow : 0; // conditional in relation to style
9d9b7755
VZ
930}
931
932// ----------------------------------------------------------------------------
933// drawing
934// ----------------------------------------------------------------------------
935
13111b2a 936void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
9d9b7755 937{
07e87221 938 wxPaintDC dc(this);
3965571c 939
9d9b7755
VZ
940 dc.SetFont(m_font);
941
3965571c 942 RecalcGeometry();
9d9b7755 943
882a8f40 944#if DEBUG_PAINT
f6bcfd97 945 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
9d9b7755
VZ
946 m_date.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
947 GetWeek(m_date));
882a8f40 948#endif
2ef31e80 949
37df1f33
VZ
950 wxCoord y = 0;
951
bb61a983 952 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
37df1f33
VZ
953 {
954 // draw the sequential month-selector
955
956 dc.SetBackgroundMode(wxTRANSPARENT);
957 dc.SetTextForeground(*wxBLACK);
958 dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID));
959 dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID));
eaf6274c 960 dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow);
37df1f33
VZ
961
962 // Get extent of month-name + year
963 wxCoord monthw, monthh;
50d0b061 964 wxString headertext = m_date.Format(wxT("%B %Y"));
37df1f33
VZ
965 dc.GetTextExtent(headertext, &monthw, &monthh);
966
967 // draw month-name centered above weekdays
968 wxCoord monthx = ((m_widthCol * 7) - monthw) / 2;
969 wxCoord monthy = ((m_heightRow - monthh) / 2) + y;
1bcf0c7d 970 dc.DrawText(headertext, monthx, monthy);
37df1f33
VZ
971
972 // calculate the "month-arrows"
973 wxPoint leftarrow[3];
974 wxPoint rightarrow[3];
975
976 int arrowheight = monthh / 2;
1bcf0c7d 977
37df1f33
VZ
978 leftarrow[0] = wxPoint(0, arrowheight / 2);
979 leftarrow[1] = wxPoint(arrowheight / 2, 0);
980 leftarrow[2] = wxPoint(arrowheight / 2, arrowheight - 1);
981
982 rightarrow[0] = wxPoint(0, 0);
983 rightarrow[1] = wxPoint(arrowheight / 2, arrowheight / 2);
984 rightarrow[2] = wxPoint(0, arrowheight - 1);
985
986 // draw the "month-arrows"
987
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);
993
994 if ( AllowMonthChange() )
995 {
996 wxDateTime ldpm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) - wxDateSpan::Day(); // last day prev month
997 // Check if range permits change
1bcf0c7d 998 if ( IsDateInRange(ldpm) && ( ( ldpm.GetYear() == m_date.GetYear() ) ? TRUE : AllowYearChange() ) )
37df1f33
VZ
999 {
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);
1006 }
1007 wxDateTime fdnm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) + wxDateSpan::Month(); // first day next month
1bcf0c7d 1008 if ( IsDateInRange(fdnm) && ( ( fdnm.GetYear() == m_date.GetYear() ) ? TRUE : AllowYearChange() ) )
37df1f33
VZ
1009 {
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);
1016 }
1017 }
1018
1019 y += m_heightRow;
1020 }
1021
2ef31e80 1022 // first draw the week days
37df1f33 1023 if ( IsExposed(0, y, 7*m_widthCol, m_heightRow) )
2ef31e80 1024 {
882a8f40 1025#if DEBUG_PAINT
f6bcfd97 1026 wxLogDebug("painting the header");
882a8f40 1027#endif
9d9b7755 1028
9d9b7755 1029 dc.SetBackgroundMode(wxTRANSPARENT);
4f6aed9c
VZ
1030 dc.SetTextForeground(m_colHeaderFg);
1031 dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID));
1032 dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID));
bb61a983 1033 dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow);
1a8557b1
VZ
1034
1035 bool startOnMonday = (GetWindowStyle() & wxCAL_MONDAY_FIRST) != 0;
1036 for ( size_t wd = 0; wd < 7; wd++ )
9d9b7755 1037 {
1a8557b1
VZ
1038 size_t n;
1039 if ( startOnMonday )
1040 n = wd == 6 ? 0 : wd + 1;
1041 else
1042 n = wd;
37df1f33
VZ
1043 wxCoord dayw, dayh;
1044 dc.GetTextExtent(m_weekdays[n], &dayw, &dayh);
37df1f33 1045 dc.DrawText(m_weekdays[n], (wd*m_widthCol) + ((m_widthCol- dayw) / 2), y); // center the day-name
9d9b7755 1046 }
2ef31e80
VZ
1047 }
1048
1049 // then the calendar itself
1050 dc.SetTextForeground(*wxBLACK);
1051 //dc.SetFont(*wxNORMAL_FONT);
1052
37df1f33 1053 y += m_heightRow;
2ef31e80 1054 wxDateTime date = GetStartDate();
37df1f33 1055
882a8f40 1056#if DEBUG_PAINT
f6bcfd97 1057 wxLogDebug("starting calendar from %s\n",
9d9b7755 1058 date.Format("%a %d-%m-%Y %H:%M:%S").c_str());
882a8f40 1059#endif
9d9b7755 1060
2ef31e80 1061 dc.SetBackgroundMode(wxSOLID);
9d9b7755 1062 for ( size_t nWeek = 1; nWeek <= 6; nWeek++, y += m_heightRow )
2ef31e80 1063 {
9d9b7755 1064 // if the update region doesn't intersect this row, don't paint it
15807266 1065 if ( !IsExposed(0, y, 7*m_widthCol, m_heightRow - 1) )
9d9b7755
VZ
1066 {
1067 date += wxDateSpan::Week();
1068
1069 continue;
1070 }
882a8f40 1071
1a8557b1 1072#if DEBUG_PAINT
f6bcfd97 1073 wxLogDebug("painting week %d at y = %d\n", nWeek, y);
882a8f40 1074#endif
9d9b7755 1075
1a8557b1 1076 for ( size_t wd = 0; wd < 7; wd++ )
2ef31e80
VZ
1077 {
1078 if ( IsDateShown(date) )
1079 {
882a8f40 1080 // don't use wxDate::Format() which prepends 0s
4f6aed9c
VZ
1081 unsigned int day = date.GetDay();
1082 wxString dayStr = wxString::Format(_T("%u"), day);
3965571c 1083 wxCoord width;
4f6aed9c
VZ
1084 dc.GetTextExtent(dayStr, &width, (wxCoord *)NULL);
1085
1086 bool changedColours = FALSE,
1087 changedFont = FALSE;
1088
1bcf0c7d 1089 bool isSel = FALSE;
37df1f33 1090 wxCalendarDateAttr *attr = NULL;
2ef31e80 1091
37df1f33 1092 if ( date.GetMonth() != m_date.GetMonth() || !IsDateInRange(date) )
2ef31e80 1093 {
37df1f33
VZ
1094 // surrounding week or out-of-range
1095 // draw "disabled"
1096 dc.SetTextForeground(*wxLIGHT_GREY);
4f6aed9c
VZ
1097 changedColours = TRUE;
1098 }
37df1f33 1099 else
4f6aed9c 1100 {
37df1f33
VZ
1101 isSel = date.IsSameDate(m_date);
1102 attr = m_attrs[day - 1];
4f6aed9c 1103
37df1f33 1104 if ( isSel )
4f6aed9c 1105 {
37df1f33
VZ
1106 dc.SetTextForeground(m_colHighlightFg);
1107 dc.SetTextBackground(m_colHighlightBg);
4f6aed9c 1108
4f6aed9c
VZ
1109 changedColours = TRUE;
1110 }
37df1f33 1111 else if ( attr )
4f6aed9c 1112 {
37df1f33
VZ
1113 wxColour colFg, colBg;
1114
1115 if ( attr->IsHoliday() )
1116 {
1117 colFg = m_colHolidayFg;
1118 colBg = m_colHolidayBg;
1119 }
1120 else
1121 {
1122 colFg = attr->GetTextColour();
1123 colBg = attr->GetBackgroundColour();
1124 }
1125
1126 if ( colFg.Ok() )
1127 {
1128 dc.SetTextForeground(colFg);
1129 changedColours = TRUE;
1130 }
1131
1132 if ( colBg.Ok() )
1133 {
1134 dc.SetTextBackground(colBg);
1135 changedColours = TRUE;
1136 }
1137
1138 if ( attr->HasFont() )
1139 {
1140 dc.SetFont(attr->GetFont());
1141 changedFont = TRUE;
1142 }
4f6aed9c 1143 }
2ef31e80
VZ
1144 }
1145
4f6aed9c
VZ
1146 wxCoord x = wd*m_widthCol + (m_widthCol - width) / 2;
1147 dc.DrawText(dayStr, x, y + 1);
2ef31e80 1148
4f6aed9c
VZ
1149 if ( !isSel && attr && attr->HasBorder() )
1150 {
1151 wxColour colBorder;
1152 if ( attr->HasBorderColour() )
1153 {
1154 colBorder = attr->GetBorderColour();
1155 }
1156 else
1157 {
1158 colBorder = m_foregroundColour;
1159 }
1160
1161 wxPen pen(colBorder, 1, wxSOLID);
1162 dc.SetPen(pen);
1163 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1164
1165 switch ( attr->GetBorder() )
1166 {
1167 case wxCAL_BORDER_SQUARE:
1168 dc.DrawRectangle(x - 2, y,
1169 width + 4, m_heightRow);
1170 break;
1171
1172 case wxCAL_BORDER_ROUND:
1173 dc.DrawEllipse(x - 2, y,
1174 width + 4, m_heightRow);
1175 break;
1176
1177 default:
1178 wxFAIL_MSG(_T("unknown border type"));
1179 }
1180 }
1181
1182 if ( changedColours )
2ef31e80 1183 {
9d9b7755 1184 dc.SetTextForeground(m_foregroundColour);
2ef31e80
VZ
1185 dc.SetTextBackground(m_backgroundColour);
1186 }
4f6aed9c
VZ
1187
1188 if ( changedFont )
1189 {
1190 dc.SetFont(m_font);
1191 }
2ef31e80
VZ
1192 }
1193 //else: just don't draw it
1194
1195 date += wxDateSpan::Day();
1196 }
2ef31e80 1197 }
37df1f33
VZ
1198
1199 // Greying out out-of-range background
1200 bool showSurrounding = (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) != 0;
1201
1202 date = ( showSurrounding ) ? GetStartDate() : wxDateTime(1, m_date.GetMonth(), m_date.GetYear());
1203 if ( !IsDateInRange(date) )
1204 {
1205 wxDateTime firstOOR = GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1206
1207 wxBrush oorbrush = *wxLIGHT_GREY_BRUSH;
1208 oorbrush.SetStyle(wxFDIAGONAL_HATCH);
1209
1210 HighlightRange(&dc, date, firstOOR, wxTRANSPARENT_PEN, &oorbrush);
1211 }
1212
1213 date = ( showSurrounding ) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear());
1214 if ( !IsDateInRange(date) )
1215 {
1216 wxDateTime firstOOR = GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1bcf0c7d 1217
37df1f33
VZ
1218 wxBrush oorbrush = *wxLIGHT_GREY_BRUSH;
1219 oorbrush.SetStyle(wxFDIAGONAL_HATCH);
1220
1221 HighlightRange(&dc, firstOOR, date, wxTRANSPARENT_PEN, &oorbrush);
1222 }
1223
882a8f40 1224#if DEBUG_PAINT
f6bcfd97 1225 wxLogDebug("+++ finished painting");
882a8f40 1226#endif
9d9b7755
VZ
1227}
1228
1229void wxCalendarCtrl::RefreshDate(const wxDateTime& date)
1230{
1231 RecalcGeometry();
1232
1233 wxRect rect;
1234
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
1238 rect.x = 0;
37df1f33
VZ
1239
1240 rect.y = (m_heightRow * GetWeek(date)) + m_rowOffset;
1241
9d9b7755
VZ
1242 rect.width = 7*m_widthCol;
1243 rect.height = m_heightRow;
1244
f6bcfd97
BP
1245#ifdef __WXMSW__
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.
1251 rect.Inflate(0, 1);
1252#endif // MSW
1253
882a8f40 1254#if DEBUG_PAINT
f6bcfd97 1255 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
9d9b7755
VZ
1256 GetWeek(date),
1257 rect.x, rect.y,
1258 rect.x + rect.width, rect.y + rect.height);
882a8f40 1259#endif
9d9b7755
VZ
1260
1261 Refresh(TRUE, &rect);
2ef31e80
VZ
1262}
1263
37df1f33
VZ
1264void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, const wxDateTime& todate, wxPen* pPen, wxBrush* pBrush)
1265{
1266 // Highlights the given range using pen and brush
1267 // Does nothing if todate < fromdate
1268
1269
1270#if DEBUG_PAINT
1271 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate.Format("%d %m %Y"), todate.Format("%d %m %Y"));
1272#endif
1273
1274 if ( todate >= fromdate )
1275 {
1276 // do stuff
1277 // date-coordinates
1bcf0c7d 1278 int fd, fw;
37df1f33
VZ
1279 int td, tw;
1280
1281 // implicit: both dates must be currently shown - checked by GetDateCoord
1282 if ( GetDateCoord(fromdate, &fd, &fw) && GetDateCoord(todate, &td, &tw) )
1283 {
1284#if DEBUG_PAINT
1285 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd, fw, td, tw);
1286#endif
1287 if ( ( (tw - fw) == 1 ) && ( td < fd ) )
1288 {
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();
1293#if DEBUG_PAINT
1294 wxLogDebug("Highlight: Seperate segments");
1295#endif
1296 // draw seperately
1297 HighlightRange(pDC, fromdate, tfd, pPen, pBrush);
1298 HighlightRange(pDC, ftd, todate, pPen, pBrush);
1299 }
1300 else
1301 {
1302 int numpoints;
1303 wxPoint corners[8]; // potentially 8 corners in polygon
1304
1305 if ( fw == tw )
1306 {
1307 // simple case: same week
1308 numpoints = 4;
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);
1313 }
1314 else
1315 {
1316 int cidx = 0;
1317 // "complex" polygon
1318 corners[cidx] = wxPoint((fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++;
1bcf0c7d 1319
37df1f33
VZ
1320 if ( fd > 1 )
1321 {
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++;
1324 }
1325
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++;
1328
1329 if ( td < 7 )
1330 {
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++;
1333 }
1334
1335 corners[cidx] = wxPoint(7 * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++;
1bcf0c7d 1336
37df1f33
VZ
1337 numpoints = cidx;
1338 }
1339
1340 // draw the polygon
1341 pDC->SetBrush(*pBrush);
1342 pDC->SetPen(*pPen);
1343 pDC->DrawPolygon(numpoints, corners);
1344 }
1345 }
1346 }
1347 // else do nothing
1348#if DEBUG_PAINT
1349 wxLogDebug("--- HighlightRange ---");
1350#endif
1351}
1352
1353bool wxCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *week) const
1354{
1bcf0c7d 1355 bool retval = TRUE;
37df1f33
VZ
1356
1357#if DEBUG_PAINT
1358 wxLogDebug("+++ GetDateCoord: (%s) +++", date.Format("%d %m %Y"));
1359#endif
1360
1361 if ( IsDateShown(date) )
1362 {
1363 bool startOnMonday = ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) != 0;
1bcf0c7d 1364
37df1f33
VZ
1365 // Find day
1366 *day = date.GetWeekDay();
1bcf0c7d 1367
37df1f33
VZ
1368 if ( *day == 0 ) // sunday
1369 {
1370 *day = ( startOnMonday ) ? 7 : 1;
1371 }
1372 else
1373 {
1374 day += ( startOnMonday ) ? 0 : 1;
1375 }
1376
1377 int targetmonth = date.GetMonth() + (12 * date.GetYear());
1378 int thismonth = m_date.GetMonth() + (12 * m_date.GetYear());
1379
1380 // Find week
1381 if ( targetmonth == thismonth )
1382 {
1383 *week = GetWeek(date);
1384 }
1385 else
1386 {
1387 if ( targetmonth < thismonth )
1388 {
1389 *week = 1; // trivial
1390 }
1391 else // targetmonth > thismonth
1392 {
1393 wxDateTime ldcm;
1394 int lastweek;
1395 int lastday;
1396
1397 // get the datecoord of the last day in the month currently shown
1398#if DEBUG_PAINT
1399 wxLogDebug(" +++ LDOM +++");
1400#endif
1401 GetDateCoord(ldcm.SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear()), &lastday, &lastweek);
1402#if DEBUG_PAINT
1403 wxLogDebug(" --- LDOM ---");
1404#endif
1405
1406 wxTimeSpan span = date - ldcm;
1407
1408 int daysfromlast = span.GetDays();
1409#if DEBUG_PAINT
1410 wxLogDebug("daysfromlast: %i", daysfromlast);
1411#endif
1412 if ( daysfromlast + lastday > 7 ) // past week boundary
1413 {
1414 int wholeweeks = (daysfromlast / 7);
1415 *week = wholeweeks + lastweek;
1416 if ( (daysfromlast - (7 * wholeweeks) + lastday) > 7 )
1417 {
1418 *week += 1;
1419 }
1420 }
1421 else
1422 {
1423 *week = lastweek;
1424 }
1425 }
1426 }
1427 }
1428 else
1429 {
1430 *day = -1;
1431 *week = -1;
1bcf0c7d 1432 retval = FALSE;
37df1f33
VZ
1433 }
1434
1435#if DEBUG_PAINT
1436 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date.Format("%d %m %Y"), *day, *week);
1437#endif
1438
1439 return retval;
1440}
1441
2ef31e80
VZ
1442// ----------------------------------------------------------------------------
1443// mouse handling
1444// ----------------------------------------------------------------------------
1445
0185cd09 1446void wxCalendarCtrl::OnDClick(wxMouseEvent& event)
2ef31e80 1447{
0185cd09 1448 if ( HitTest(event.GetPosition()) != wxCAL_HITTEST_DAY )
2ef31e80
VZ
1449 {
1450 event.Skip();
1451 }
1452 else
1453 {
4f6aed9c 1454 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
0185cd09
VZ
1455 }
1456}
1457
1458void wxCalendarCtrl::OnClick(wxMouseEvent& event)
1459{
1460 wxDateTime date;
1461 wxDateTime::WeekDay wday;
1462 switch ( HitTest(event.GetPosition(), &date, &wday) )
1463 {
1464 case wxCAL_HITTEST_DAY:
37df1f33
VZ
1465 if ( IsDateInRange(date) )
1466 {
1467 ChangeDay(date);
2ef31e80 1468
37df1f33
VZ
1469 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED,
1470 wxEVT_CALENDAR_SEL_CHANGED);
1471 }
0185cd09
VZ
1472 break;
1473
1474 case wxCAL_HITTEST_HEADER:
1475 {
1476 wxCalendarEvent event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED);
1477 event.m_wday = wday;
1478 (void)GetEventHandler()->ProcessEvent(event);
1479 }
1480 break;
1481
37df1f33
VZ
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?)
1486 break;
1487
0185cd09
VZ
1488 default:
1489 wxFAIL_MSG(_T("unknown hittest code"));
1490 // fall through
1491
1492 case wxCAL_HITTEST_NOWHERE:
1493 event.Skip();
1494 break;
2ef31e80
VZ
1495 }
1496}
1497
0185cd09
VZ
1498wxCalendarHitTestResult wxCalendarCtrl::HitTest(const wxPoint& pos,
1499 wxDateTime *date,
1500 wxDateTime::WeekDay *wd)
2ef31e80 1501{
9d9b7755
VZ
1502 RecalcGeometry();
1503
2ef31e80 1504 wxCoord y = pos.y;
37df1f33
VZ
1505
1506///////////////////////////////////////////////////////////////////////////////////////////////////////
1507 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
0185cd09 1508 {
37df1f33 1509 // Header: month
1bcf0c7d 1510
37df1f33
VZ
1511 // we need to find out if the hit is on left arrow, on month or on right arrow
1512 // left arrow?
1513 if ( wxRegion(m_leftArrowRect).Contains(pos) == wxInRegion )
0185cd09 1514 {
37df1f33 1515 if ( date )
0185cd09 1516 {
37df1f33
VZ
1517 if ( IsDateInRange(m_date - wxDateSpan::Month()) )
1518 {
1519 *date = m_date - wxDateSpan::Month();
1520 }
1521 else
1522 {
1523 *date = GetLowerDateLimit();
1524 }
1525 }
1526
1527 return wxCAL_HITTEST_DECMONTH;
1528 }
1529
1530 if ( wxRegion(m_rightArrowRect).Contains(pos) == wxInRegion )
1531 {
1532 if ( date )
1533 {
1534 if ( IsDateInRange(m_date + wxDateSpan::Month()) )
1535 {
1536 *date = m_date + wxDateSpan::Month();
1537 }
1538 else
1539 {
1540 *date = GetUpperDateLimit();
1541 }
0185cd09
VZ
1542 }
1543
37df1f33 1544 return wxCAL_HITTEST_INCMONTH;
0185cd09 1545 }
2ef31e80 1546
0185cd09 1547 }
2ef31e80 1548
37df1f33
VZ
1549///////////////////////////////////////////////////////////////////////////////////////////////////////
1550 // Header: Days
1551 int wday = pos.x / m_widthCol;
1552// if ( y < m_heightRow )
1553 if ( y < (m_heightRow + m_rowOffset) )
1554 {
1555 if ( y > m_rowOffset )
1556 {
1557 if ( wd )
1558 {
1559 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST )
1560 {
1561 wday = wday == 6 ? 0 : wday + 1;
1562 }
1563
1564 *wd = (wxDateTime::WeekDay)wday;
1565 }
1566
1567 return wxCAL_HITTEST_HEADER;
1568 }
1569 else
1570 {
1571 return wxCAL_HITTEST_NOWHERE;
1572 }
1573 }
1574
1575// int week = (y - m_heightRow) / m_heightRow;
1576 int week = (y - (m_heightRow + m_rowOffset)) / m_heightRow;
2ef31e80 1577 if ( week >= 6 || wday >= 7 )
0185cd09
VZ
1578 {
1579 return wxCAL_HITTEST_NOWHERE;
1580 }
2ef31e80 1581
0185cd09 1582 wxDateTime dt = GetStartDate() + wxDateSpan::Days(7*week + wday);
2ef31e80 1583
0185cd09
VZ
1584 if ( IsDateShown(dt) )
1585 {
1586 if ( date )
1587 *date = dt;
9d9b7755 1588
37df1f33
VZ
1589 if ( dt.GetMonth() == m_date.GetMonth() )
1590 {
1591
1592 return wxCAL_HITTEST_DAY;
1593 }
1594 else
1595 {
1596 return wxCAL_HITTEST_SURROUNDING_WEEK;
1597 }
0185cd09
VZ
1598 }
1599 else
1600 {
1601 return wxCAL_HITTEST_NOWHERE;
1602 }
2ef31e80 1603}
9d9b7755
VZ
1604
1605// ----------------------------------------------------------------------------
1606// subcontrols events handling
1607// ----------------------------------------------------------------------------
1608
1609void wxCalendarCtrl::OnMonthChange(wxCommandEvent& event)
1610{
1611 wxDateTime::Tm tm = m_date.GetTm();
1612
1613 wxDateTime::Month mon = (wxDateTime::Month)event.GetInt();
1614 if ( tm.mday > wxDateTime::GetNumberOfDays(mon, tm.year) )
1615 {
1616 tm.mday = wxDateTime::GetNumberOfDays(mon, tm.year);
1617 }
1618
37df1f33
VZ
1619 wxDateTime target = wxDateTime(tm.mday, mon, tm.year);
1620
1621 ChangeMonth(&target);
1622 SetDateAndNotify(target);
9d9b7755
VZ
1623}
1624
f0d5e7a2 1625void wxCalendarCtrl::OnYearChange(wxCommandEvent& event)
9d9b7755 1626{
f0d5e7a2
VZ
1627 int year = (int)event.GetInt();
1628 if ( year == INT_MIN )
1629 {
1630 // invalid year in the spin control, ignore it
1631 return;
1632 }
1633
9d9b7755
VZ
1634 wxDateTime::Tm tm = m_date.GetTm();
1635
9d9b7755
VZ
1636 if ( tm.mday > wxDateTime::GetNumberOfDays(tm.mon, year) )
1637 {
1638 tm.mday = wxDateTime::GetNumberOfDays(tm.mon, year);
1639 }
1bcf0c7d 1640
37df1f33
VZ
1641 wxDateTime target = wxDateTime(tm.mday, tm.mon, year);
1642
1643 if ( ChangeYear(&target) )
1644 {
1645 SetDateAndNotify(target);
1646 }
1647 else
1648 {
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());
1652 }
9d9b7755
VZ
1653}
1654
1655// ----------------------------------------------------------------------------
1656// keyboard interface
1657// ----------------------------------------------------------------------------
1658
1659void wxCalendarCtrl::OnChar(wxKeyEvent& event)
1660{
37df1f33 1661 wxDateTime target;
12a3f227 1662 switch ( event.GetKeyCode() )
9d9b7755
VZ
1663 {
1664 case _T('+'):
1665 case WXK_ADD:
37df1f33
VZ
1666 target = m_date + wxDateSpan::Year();
1667 if ( ChangeYear(&target) )
1668 {
1669 SetDateAndNotify(target);
1670 }
9d9b7755
VZ
1671 break;
1672
1673 case _T('-'):
1674 case WXK_SUBTRACT:
37df1f33
VZ
1675 target = m_date - wxDateSpan::Year();
1676 if ( ChangeYear(&target) )
1677 {
1678 SetDateAndNotify(target);
1679 }
9d9b7755
VZ
1680 break;
1681
882a8f40 1682 case WXK_PRIOR:
37df1f33
VZ
1683 target = m_date - wxDateSpan::Month();
1684 ChangeMonth(&target);
1685 SetDateAndNotify(target); // always
9d9b7755
VZ
1686 break;
1687
882a8f40 1688 case WXK_NEXT:
37df1f33
VZ
1689 target = m_date + wxDateSpan::Month();
1690 ChangeMonth(&target);
1691 SetDateAndNotify(target); // always
9d9b7755
VZ
1692 break;
1693
1694 case WXK_RIGHT:
1a8557b1 1695 if ( event.ControlDown() )
37df1f33
VZ
1696 {
1697 target = wxDateTime(m_date).SetToNextWeekDay(
1a8557b1 1698 GetWindowStyle() & wxCAL_MONDAY_FIRST
37df1f33
VZ
1699 ? wxDateTime::Sun : wxDateTime::Sat);
1700 if ( !IsDateInRange(target) )
1701 {
1702 target = GetUpperDateLimit();
1703 }
1704 SetDateAndNotify(target);
1705 }
1a8557b1
VZ
1706 else
1707 SetDateAndNotify(m_date + wxDateSpan::Day());
9d9b7755
VZ
1708 break;
1709
1710 case WXK_LEFT:
1a8557b1 1711 if ( event.ControlDown() )
37df1f33
VZ
1712 {
1713 target = wxDateTime(m_date).SetToPrevWeekDay(
1a8557b1 1714 GetWindowStyle() & wxCAL_MONDAY_FIRST
37df1f33
VZ
1715 ? wxDateTime::Mon : wxDateTime::Sun);
1716 if ( !IsDateInRange(target) )
1717 {
1718 target = GetLowerDateLimit();
1719 }
1720 SetDateAndNotify(target);
1721 }
1a8557b1
VZ
1722 else
1723 SetDateAndNotify(m_date - wxDateSpan::Day());
9d9b7755
VZ
1724 break;
1725
1726 case WXK_UP:
1727 SetDateAndNotify(m_date - wxDateSpan::Week());
1728 break;
1729
1730 case WXK_DOWN:
1731 SetDateAndNotify(m_date + wxDateSpan::Week());
1732 break;
1733
1734 case WXK_HOME:
1a8557b1
VZ
1735 if ( event.ControlDown() )
1736 SetDateAndNotify(wxDateTime::Today());
1737 else
1738 SetDateAndNotify(wxDateTime(1, m_date.GetMonth(), m_date.GetYear()));
1739 break;
1740
1741 case WXK_END:
1742 SetDateAndNotify(wxDateTime(m_date).SetToLastMonthDay());
9d9b7755
VZ
1743 break;
1744
4f6aed9c
VZ
1745 case WXK_RETURN:
1746 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
1747 break;
1748
9d9b7755
VZ
1749 default:
1750 event.Skip();
1751 }
1752}
1753
1754// ----------------------------------------------------------------------------
4f6aed9c 1755// holidays handling
9d9b7755
VZ
1756// ----------------------------------------------------------------------------
1757
4f6aed9c 1758void wxCalendarCtrl::EnableHolidayDisplay(bool display)
9d9b7755 1759{
4f6aed9c
VZ
1760 long style = GetWindowStyle();
1761 if ( display )
1762 style |= wxCAL_SHOW_HOLIDAYS;
1763 else
1764 style &= ~wxCAL_SHOW_HOLIDAYS;
1765
1766 SetWindowStyle(style);
1767
1768 if ( display )
1769 SetHolidayAttrs();
1770 else
1771 ResetHolidayAttrs();
1772
1773 Refresh();
1774}
1775
1776void wxCalendarCtrl::SetHolidayAttrs()
1777{
1778 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS )
1779 {
1780 ResetHolidayAttrs();
1781
1782 wxDateTime::Tm tm = m_date.GetTm();
1783 wxDateTime dtStart(1, tm.mon, tm.year),
1784 dtEnd = dtStart.GetLastMonthDay();
1785
1786 wxDateTimeArray hol;
1787 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart, dtEnd, hol);
1788
1789 size_t count = hol.GetCount();
1790 for ( size_t n = 0; n < count; n++ )
1791 {
1792 SetHoliday(hol[n].GetDay());
1793 }
1794 }
1795}
1796
1797void wxCalendarCtrl::SetHoliday(size_t day)
1798{
1799 wxCHECK_RET( day > 0 && day < 32, _T("invalid day in SetHoliday") );
0185cd09 1800
4f6aed9c
VZ
1801 wxCalendarDateAttr *attr = GetAttr(day);
1802 if ( !attr )
0185cd09 1803 {
4f6aed9c
VZ
1804 attr = new wxCalendarDateAttr;
1805 }
0185cd09 1806
4f6aed9c
VZ
1807 attr->SetHoliday(TRUE);
1808
1809 // can't use SetAttr() because it would delete this pointer
1810 m_attrs[day - 1] = attr;
1811}
1812
1813void wxCalendarCtrl::ResetHolidayAttrs()
1814{
1815 for ( size_t day = 0; day < 31; day++ )
1816 {
1817 if ( m_attrs[day] )
1818 {
1819 m_attrs[day]->SetHoliday(FALSE);
1820 }
0185cd09
VZ
1821 }
1822}
1823
4f6aed9c
VZ
1824// ----------------------------------------------------------------------------
1825// wxCalendarEvent
1826// ----------------------------------------------------------------------------
1827
0185cd09
VZ
1828void wxCalendarEvent::Init()
1829{
1830 m_wday = wxDateTime::Inv_WeekDay;
9d9b7755
VZ
1831}
1832
1833wxCalendarEvent::wxCalendarEvent(wxCalendarCtrl *cal, wxEventType type)
1834 : wxCommandEvent(type, cal->GetId())
1835{
1836 m_date = cal->GetDate();
4fa54a31 1837 SetEventObject(cal);
9d9b7755 1838}
2fa7c206 1839
1e6feb95 1840#endif // wxUSE_CALENDARCTRL
2fa7c206 1841