]> git.saurik.com Git - wxWidgets.git/blame - src/generic/calctrl.cpp
concentrating content and structure region calculations
[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)
cb0afb26 126 wxFLAGS_MEMBER(wxBORDER)
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)
cb0afb26 133 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3ff066a4
SC
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{
37df1f33 671 // Check if the given date is in the range specified
999836aa 672 return ( ( ( m_lowdate.IsValid() ) ? ( date >= m_lowdate ) : TRUE )
1bcf0c7d 673 && ( ( m_highdate.IsValid() ) ? ( date <= m_highdate ) : TRUE ) );
37df1f33
VZ
674}
675
676bool wxCalendarCtrl::ChangeYear(wxDateTime* target) const
677{
1bcf0c7d 678 bool retval = FALSE;
37df1f33
VZ
679
680 if ( !(IsDateInRange(*target)) )
681 {
682 if ( target->GetYear() < m_date.GetYear() )
683 {
684 if ( target->GetYear() >= GetLowerDateLimit().GetYear() )
685 {
686 *target = GetLowerDateLimit();
1bcf0c7d 687 retval = TRUE;
37df1f33
VZ
688 }
689 else
690 {
691 *target = m_date;
692 }
693 }
694 else
695 {
696 if ( target->GetYear() <= GetUpperDateLimit().GetYear() )
697 {
698 *target = GetUpperDateLimit();
1bcf0c7d 699 retval = TRUE;
37df1f33
VZ
700 }
701 else
702 {
703 *target = m_date;
704 }
705 }
706 }
707 else
708 {
1bcf0c7d 709 retval = TRUE;
37df1f33
VZ
710 }
711
712 return retval;
713}
714
715bool wxCalendarCtrl::ChangeMonth(wxDateTime* target) const
716{
1bcf0c7d 717 bool retval = TRUE;
37df1f33
VZ
718
719 if ( !(IsDateInRange(*target)) )
720 {
1bcf0c7d 721 retval = FALSE;
37df1f33
VZ
722
723 if ( target->GetMonth() < m_date.GetMonth() )
724 {
725 *target = GetLowerDateLimit();
726 }
727 else
728 {
729 *target = GetUpperDateLimit();
730 }
731 }
732
733 return retval;
2ef31e80
VZ
734}
735
9d9b7755
VZ
736size_t wxCalendarCtrl::GetWeek(const wxDateTime& date) const
737{
37df1f33
VZ
738 size_t retval = date.GetWeekOfMonth(GetWindowStyle() & wxCAL_MONDAY_FIRST
739 ? wxDateTime::Monday_First
740 : wxDateTime::Sunday_First);
741
742 if ( (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) )
743 {
744 // we need to offset an extra week if we "start" on the 1st of the month
745 wxDateTime::Tm tm = date.GetTm();
746
747 wxDateTime datetest = wxDateTime(1, tm.mon, tm.year);
748
749 // rewind back
750 datetest.SetToPrevWeekDay(GetWindowStyle() & wxCAL_MONDAY_FIRST
751 ? wxDateTime::Mon : wxDateTime::Sun);
1bcf0c7d 752
37df1f33
VZ
753 if ( datetest.GetDay() == 1 )
754 {
755 retval += 1;
756 }
757 }
1bcf0c7d 758
37df1f33 759 return retval;
9d9b7755
VZ
760}
761
2ef31e80
VZ
762// ----------------------------------------------------------------------------
763// size management
764// ----------------------------------------------------------------------------
765
9d9b7755
VZ
766// this is a composite control and it must arrange its parts each time its
767// size or position changes: the combobox and spinctrl are along the top of
768// the available area and the calendar takes up therest of the space
769
bc385ba9
VZ
770// the static controls are supposed to be always smaller than combo/spin so we
771// always use the latter for size calculations and position the static to take
772// the same space
773
9d9b7755
VZ
774// the constants used for the layout
775#define VERT_MARGIN 5 // distance between combo and calendar
81b6ccf1
SC
776#ifdef __WXMAC__
777#define HORZ_MARGIN 5 // spin
778#else
9d9b7755 779#define HORZ_MARGIN 15 // spin
81b6ccf1 780#endif
2ef31e80
VZ
781wxSize wxCalendarCtrl::DoGetBestSize() const
782{
9d9b7755
VZ
783 // calc the size of the calendar
784 ((wxCalendarCtrl *)this)->RecalcGeometry(); // const_cast
785
786 wxCoord width = 7*m_widthCol,
bb61a983 787 height = 7*m_heightRow + m_rowOffset + VERT_MARGIN;
9d9b7755 788
bb61a983 789 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
37df1f33 790 {
bb61a983
VZ
791 // the combobox doesn't report its height correctly (it returns the
792 // height including the drop down list) so don't use it
793 height += m_spinYear->GetBestSize().y;
37df1f33
VZ
794 }
795
bb61a983 796 if ( !HasFlag(wxBORDER_NONE) )
bc385ba9
VZ
797 {
798 // the border would clip the last line otherwise
f41cb81e 799 height += 6;
37df1f33 800 width += 4;
bc385ba9
VZ
801 }
802
9d9b7755 803 return wxSize(width, height);
2ef31e80
VZ
804}
805
806void wxCalendarCtrl::DoSetSize(int x, int y,
807 int width, int height,
808 int sizeFlags)
809{
810 wxControl::DoSetSize(x, y, width, height, sizeFlags);
811}
812
813void wxCalendarCtrl::DoMoveWindow(int x, int y, int width, int height)
814{
bb61a983 815 int yDiff;
2ef31e80 816
bb61a983 817 if ( !HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
37df1f33
VZ
818 {
819 wxSize sizeCombo = m_comboMonth->GetSize();
820 wxSize sizeStatic = m_staticMonth->GetSize();
95bcc40c 821 wxSize sizeSpin = m_spinYear->GetSize();
37df1f33 822 int dy = (sizeCombo.y - sizeStatic.y) / 2;
e910c000
JS
823/*
824In the calender the size of the combobox for the year
825is just defined by a margin from the month combobox to
826the left border. While in wxUniv the year control can't
827show all 4 digits, in wxMsw it show almost twice as
828much. Instead the year should use it's best size and be
829left aligned to the calendar. Just in case the month in
830any language is longer than it has space in the
831calendar it is shortend.This way the year always can
832show the 4 digits.
833
834This patch relies on the fact that a combobox has a
835good best size implementation. This is not the case
836with wxMSW but I don't know why.
837
838Otto Wyss
839*/
840
841#ifdef __WXUNIVERSAL__
95bcc40c
JS
842 if (sizeCombo.x + HORZ_MARGIN - sizeSpin.x > width)
843 {
844 m_comboMonth->SetSize(x, y, width - HORZ_MARGIN - sizeSpin.x, sizeCombo.y);
845 }
846 else
847 {
848 m_comboMonth->Move(x, y);
849 }
850 m_staticMonth->Move(x, y + dy);
851 m_spinYear->Move(x + width - sizeSpin.x, y);
852 m_staticYear->Move(x + width - sizeSpin.x, y + dy);
e910c000
JS
853#else
854 m_comboMonth->Move(x, y);
855 m_staticMonth->SetSize(x, y + dy, sizeCombo.x, sizeStatic.y);
37df1f33 856
e910c000
JS
857 int xDiff = sizeCombo.x + HORZ_MARGIN;
858
859 m_spinYear->SetSize(x + xDiff, y, width - xDiff, sizeCombo.y);
860 m_staticYear->SetSize(x + xDiff, y + dy, width - xDiff, sizeStatic.y);
861#endif
37df1f33
VZ
862 yDiff = wxMax(sizeSpin.y, sizeCombo.y) + VERT_MARGIN;
863 }
bb61a983
VZ
864 else // no controls on the top
865 {
866 yDiff = 0;
867 }
9d9b7755
VZ
868
869 wxControl::DoMoveWindow(x, y + yDiff, width, height - yDiff);
870}
871
882a8f40
VZ
872void wxCalendarCtrl::DoGetPosition(int *x, int *y) const
873{
874 wxControl::DoGetPosition(x, y);
875
37df1f33 876 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
882a8f40 877 {
37df1f33
VZ
878 // our real top corner is not in this position
879 if ( y )
880 {
881 *y -= GetMonthControl()->GetSize().y + VERT_MARGIN;
882 }
882a8f40
VZ
883 }
884}
885
886void wxCalendarCtrl::DoGetSize(int *width, int *height) const
887{
888 wxControl::DoGetSize(width, height);
889
37df1f33 890 if ( !(GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
882a8f40 891 {
37df1f33 892 // our real height is bigger
5b3610da 893 if ( height && GetMonthControl())
37df1f33
VZ
894 {
895 *height += GetMonthControl()->GetSize().y + VERT_MARGIN;
896 }
882a8f40
VZ
897 }
898}
899
9d9b7755 900void wxCalendarCtrl::RecalcGeometry()
2ef31e80 901{
9d9b7755
VZ
902 if ( m_widthCol != 0 )
903 return;
2ef31e80 904
9d9b7755 905 wxClientDC dc(this);
3965571c 906
9d9b7755 907 dc.SetFont(m_font);
3965571c 908
2ef31e80
VZ
909 // determine the column width (we assume that the weekday names are always
910 // wider (in any language) than the numbers)
911 m_widthCol = 0;
9d9b7755 912 wxDateTime::WeekDay wd;
2ef31e80
VZ
913 for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) )
914 {
2ef31e80 915 wxCoord width;
9d9b7755 916 dc.GetTextExtent(m_weekdays[wd], &width, &m_heightRow);
2ef31e80
VZ
917 if ( width > m_widthCol )
918 {
919 m_widthCol = width;
920 }
921 }
3965571c 922
2ef31e80
VZ
923 // leave some margins
924 m_widthCol += 2;
925 m_heightRow += 2;
37df1f33
VZ
926
927 m_rowOffset = (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) ? m_heightRow : 0; // conditional in relation to style
9d9b7755
VZ
928}
929
930// ----------------------------------------------------------------------------
931// drawing
932// ----------------------------------------------------------------------------
933
13111b2a 934void wxCalendarCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
9d9b7755 935{
07e87221 936 wxPaintDC dc(this);
3965571c 937
9d9b7755
VZ
938 dc.SetFont(m_font);
939
3965571c 940 RecalcGeometry();
9d9b7755 941
882a8f40 942#if DEBUG_PAINT
f6bcfd97 943 wxLogDebug("--- starting to paint, selection: %s, week %u\n",
9d9b7755
VZ
944 m_date.Format("%a %d-%m-%Y %H:%M:%S").c_str(),
945 GetWeek(m_date));
882a8f40 946#endif
2ef31e80 947
37df1f33
VZ
948 wxCoord y = 0;
949
bb61a983 950 if ( HasFlag(wxCAL_SEQUENTIAL_MONTH_SELECTION) )
37df1f33
VZ
951 {
952 // draw the sequential month-selector
953
954 dc.SetBackgroundMode(wxTRANSPARENT);
955 dc.SetTextForeground(*wxBLACK);
956 dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID));
957 dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID));
eaf6274c 958 dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow);
37df1f33
VZ
959
960 // Get extent of month-name + year
961 wxCoord monthw, monthh;
50d0b061 962 wxString headertext = m_date.Format(wxT("%B %Y"));
37df1f33
VZ
963 dc.GetTextExtent(headertext, &monthw, &monthh);
964
965 // draw month-name centered above weekdays
966 wxCoord monthx = ((m_widthCol * 7) - monthw) / 2;
967 wxCoord monthy = ((m_heightRow - monthh) / 2) + y;
1bcf0c7d 968 dc.DrawText(headertext, monthx, monthy);
37df1f33
VZ
969
970 // calculate the "month-arrows"
971 wxPoint leftarrow[3];
972 wxPoint rightarrow[3];
973
974 int arrowheight = monthh / 2;
1bcf0c7d 975
37df1f33
VZ
976 leftarrow[0] = wxPoint(0, arrowheight / 2);
977 leftarrow[1] = wxPoint(arrowheight / 2, 0);
978 leftarrow[2] = wxPoint(arrowheight / 2, arrowheight - 1);
979
980 rightarrow[0] = wxPoint(0, 0);
981 rightarrow[1] = wxPoint(arrowheight / 2, arrowheight / 2);
982 rightarrow[2] = wxPoint(0, arrowheight - 1);
983
984 // draw the "month-arrows"
985
986 wxCoord arrowy = (m_heightRow - arrowheight) / 2;
987 wxCoord larrowx = (m_widthCol - (arrowheight / 2)) / 2;
988 wxCoord rarrowx = ((m_widthCol - (arrowheight / 2)) / 2) + m_widthCol*6;
989 m_leftArrowRect = wxRect(0, 0, 0, 0);
990 m_rightArrowRect = wxRect(0, 0, 0, 0);
991
992 if ( AllowMonthChange() )
993 {
994 wxDateTime ldpm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) - wxDateSpan::Day(); // last day prev month
995 // Check if range permits change
1bcf0c7d 996 if ( IsDateInRange(ldpm) && ( ( ldpm.GetYear() == m_date.GetYear() ) ? TRUE : AllowYearChange() ) )
37df1f33
VZ
997 {
998 m_leftArrowRect = wxRect(larrowx - 3, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6));
999 dc.SetBrush(wxBrush(*wxBLACK, wxSOLID));
1000 dc.SetPen(wxPen(*wxBLACK, 1, wxSOLID));
1001 dc.DrawPolygon(3, leftarrow, larrowx , arrowy, wxWINDING_RULE);
1002 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1003 dc.DrawRectangle(m_leftArrowRect);
1004 }
1005 wxDateTime fdnm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) + wxDateSpan::Month(); // first day next month
1bcf0c7d 1006 if ( IsDateInRange(fdnm) && ( ( fdnm.GetYear() == m_date.GetYear() ) ? TRUE : AllowYearChange() ) )
37df1f33
VZ
1007 {
1008 m_rightArrowRect = wxRect(rarrowx - 4, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6));
1009 dc.SetBrush(wxBrush(*wxBLACK, wxSOLID));
1010 dc.SetPen(wxPen(*wxBLACK, 1, wxSOLID));
1011 dc.DrawPolygon(3, rightarrow, rarrowx , arrowy, wxWINDING_RULE);
1012 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1013 dc.DrawRectangle(m_rightArrowRect);
1014 }
1015 }
1016
1017 y += m_heightRow;
1018 }
1019
2ef31e80 1020 // first draw the week days
37df1f33 1021 if ( IsExposed(0, y, 7*m_widthCol, m_heightRow) )
2ef31e80 1022 {
882a8f40 1023#if DEBUG_PAINT
f6bcfd97 1024 wxLogDebug("painting the header");
882a8f40 1025#endif
9d9b7755 1026
9d9b7755 1027 dc.SetBackgroundMode(wxTRANSPARENT);
4f6aed9c
VZ
1028 dc.SetTextForeground(m_colHeaderFg);
1029 dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID));
1030 dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID));
bb61a983 1031 dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow);
1a8557b1
VZ
1032
1033 bool startOnMonday = (GetWindowStyle() & wxCAL_MONDAY_FIRST) != 0;
1034 for ( size_t wd = 0; wd < 7; wd++ )
9d9b7755 1035 {
1a8557b1
VZ
1036 size_t n;
1037 if ( startOnMonday )
1038 n = wd == 6 ? 0 : wd + 1;
1039 else
1040 n = wd;
37df1f33
VZ
1041 wxCoord dayw, dayh;
1042 dc.GetTextExtent(m_weekdays[n], &dayw, &dayh);
37df1f33 1043 dc.DrawText(m_weekdays[n], (wd*m_widthCol) + ((m_widthCol- dayw) / 2), y); // center the day-name
9d9b7755 1044 }
2ef31e80
VZ
1045 }
1046
1047 // then the calendar itself
1048 dc.SetTextForeground(*wxBLACK);
1049 //dc.SetFont(*wxNORMAL_FONT);
1050
37df1f33 1051 y += m_heightRow;
2ef31e80 1052 wxDateTime date = GetStartDate();
37df1f33 1053
882a8f40 1054#if DEBUG_PAINT
f6bcfd97 1055 wxLogDebug("starting calendar from %s\n",
9d9b7755 1056 date.Format("%a %d-%m-%Y %H:%M:%S").c_str());
882a8f40 1057#endif
9d9b7755 1058
2ef31e80 1059 dc.SetBackgroundMode(wxSOLID);
9d9b7755 1060 for ( size_t nWeek = 1; nWeek <= 6; nWeek++, y += m_heightRow )
2ef31e80 1061 {
9d9b7755 1062 // if the update region doesn't intersect this row, don't paint it
15807266 1063 if ( !IsExposed(0, y, 7*m_widthCol, m_heightRow - 1) )
9d9b7755
VZ
1064 {
1065 date += wxDateSpan::Week();
1066
1067 continue;
1068 }
882a8f40 1069
1a8557b1 1070#if DEBUG_PAINT
f6bcfd97 1071 wxLogDebug("painting week %d at y = %d\n", nWeek, y);
882a8f40 1072#endif
9d9b7755 1073
1a8557b1 1074 for ( size_t wd = 0; wd < 7; wd++ )
2ef31e80
VZ
1075 {
1076 if ( IsDateShown(date) )
1077 {
882a8f40 1078 // don't use wxDate::Format() which prepends 0s
4f6aed9c
VZ
1079 unsigned int day = date.GetDay();
1080 wxString dayStr = wxString::Format(_T("%u"), day);
3965571c 1081 wxCoord width;
4f6aed9c
VZ
1082 dc.GetTextExtent(dayStr, &width, (wxCoord *)NULL);
1083
1084 bool changedColours = FALSE,
1085 changedFont = FALSE;
1086
1bcf0c7d 1087 bool isSel = FALSE;
37df1f33 1088 wxCalendarDateAttr *attr = NULL;
2ef31e80 1089
37df1f33 1090 if ( date.GetMonth() != m_date.GetMonth() || !IsDateInRange(date) )
2ef31e80 1091 {
37df1f33
VZ
1092 // surrounding week or out-of-range
1093 // draw "disabled"
1094 dc.SetTextForeground(*wxLIGHT_GREY);
4f6aed9c
VZ
1095 changedColours = TRUE;
1096 }
37df1f33 1097 else
4f6aed9c 1098 {
37df1f33
VZ
1099 isSel = date.IsSameDate(m_date);
1100 attr = m_attrs[day - 1];
4f6aed9c 1101
37df1f33 1102 if ( isSel )
4f6aed9c 1103 {
37df1f33
VZ
1104 dc.SetTextForeground(m_colHighlightFg);
1105 dc.SetTextBackground(m_colHighlightBg);
4f6aed9c 1106
4f6aed9c
VZ
1107 changedColours = TRUE;
1108 }
37df1f33 1109 else if ( attr )
4f6aed9c 1110 {
37df1f33
VZ
1111 wxColour colFg, colBg;
1112
1113 if ( attr->IsHoliday() )
1114 {
1115 colFg = m_colHolidayFg;
1116 colBg = m_colHolidayBg;
1117 }
1118 else
1119 {
1120 colFg = attr->GetTextColour();
1121 colBg = attr->GetBackgroundColour();
1122 }
1123
1124 if ( colFg.Ok() )
1125 {
1126 dc.SetTextForeground(colFg);
1127 changedColours = TRUE;
1128 }
1129
1130 if ( colBg.Ok() )
1131 {
1132 dc.SetTextBackground(colBg);
1133 changedColours = TRUE;
1134 }
1135
1136 if ( attr->HasFont() )
1137 {
1138 dc.SetFont(attr->GetFont());
1139 changedFont = TRUE;
1140 }
4f6aed9c 1141 }
2ef31e80
VZ
1142 }
1143
4f6aed9c
VZ
1144 wxCoord x = wd*m_widthCol + (m_widthCol - width) / 2;
1145 dc.DrawText(dayStr, x, y + 1);
2ef31e80 1146
4f6aed9c
VZ
1147 if ( !isSel && attr && attr->HasBorder() )
1148 {
1149 wxColour colBorder;
1150 if ( attr->HasBorderColour() )
1151 {
1152 colBorder = attr->GetBorderColour();
1153 }
1154 else
1155 {
1156 colBorder = m_foregroundColour;
1157 }
1158
1159 wxPen pen(colBorder, 1, wxSOLID);
1160 dc.SetPen(pen);
1161 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1162
1163 switch ( attr->GetBorder() )
1164 {
1165 case wxCAL_BORDER_SQUARE:
1166 dc.DrawRectangle(x - 2, y,
1167 width + 4, m_heightRow);
1168 break;
1169
1170 case wxCAL_BORDER_ROUND:
1171 dc.DrawEllipse(x - 2, y,
1172 width + 4, m_heightRow);
1173 break;
1174
1175 default:
1176 wxFAIL_MSG(_T("unknown border type"));
1177 }
1178 }
1179
1180 if ( changedColours )
2ef31e80 1181 {
9d9b7755 1182 dc.SetTextForeground(m_foregroundColour);
2ef31e80
VZ
1183 dc.SetTextBackground(m_backgroundColour);
1184 }
4f6aed9c
VZ
1185
1186 if ( changedFont )
1187 {
1188 dc.SetFont(m_font);
1189 }
2ef31e80
VZ
1190 }
1191 //else: just don't draw it
1192
1193 date += wxDateSpan::Day();
1194 }
2ef31e80 1195 }
37df1f33
VZ
1196
1197 // Greying out out-of-range background
1198 bool showSurrounding = (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) != 0;
1199
1200 date = ( showSurrounding ) ? GetStartDate() : wxDateTime(1, m_date.GetMonth(), m_date.GetYear());
1201 if ( !IsDateInRange(date) )
1202 {
1203 wxDateTime firstOOR = GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1204
1205 wxBrush oorbrush = *wxLIGHT_GREY_BRUSH;
1206 oorbrush.SetStyle(wxFDIAGONAL_HATCH);
1207
1208 HighlightRange(&dc, date, firstOOR, wxTRANSPARENT_PEN, &oorbrush);
1209 }
1210
1211 date = ( showSurrounding ) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear());
1212 if ( !IsDateInRange(date) )
1213 {
1214 wxDateTime firstOOR = GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1bcf0c7d 1215
37df1f33
VZ
1216 wxBrush oorbrush = *wxLIGHT_GREY_BRUSH;
1217 oorbrush.SetStyle(wxFDIAGONAL_HATCH);
1218
1219 HighlightRange(&dc, firstOOR, date, wxTRANSPARENT_PEN, &oorbrush);
1220 }
1221
882a8f40 1222#if DEBUG_PAINT
f6bcfd97 1223 wxLogDebug("+++ finished painting");
882a8f40 1224#endif
9d9b7755
VZ
1225}
1226
1227void wxCalendarCtrl::RefreshDate(const wxDateTime& date)
1228{
1229 RecalcGeometry();
1230
1231 wxRect rect;
1232
1233 // always refresh the whole row at once because our OnPaint() will draw
1234 // the whole row anyhow - and this allows the small optimisation in
1235 // OnClick() below to work
1236 rect.x = 0;
37df1f33
VZ
1237
1238 rect.y = (m_heightRow * GetWeek(date)) + m_rowOffset;
1239
9d9b7755
VZ
1240 rect.width = 7*m_widthCol;
1241 rect.height = m_heightRow;
1242
f6bcfd97
BP
1243#ifdef __WXMSW__
1244 // VZ: for some reason, the selected date seems to occupy more space under
1245 // MSW - this is probably some bug in the font size calculations, but I
1246 // don't know where exactly. This fix is ugly and leads to more
1247 // refreshes than really needed, but without it the selected days
1248 // leaves even more ugly underscores on screen.
1249 rect.Inflate(0, 1);
1250#endif // MSW
1251
882a8f40 1252#if DEBUG_PAINT
f6bcfd97 1253 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
9d9b7755
VZ
1254 GetWeek(date),
1255 rect.x, rect.y,
1256 rect.x + rect.width, rect.y + rect.height);
882a8f40 1257#endif
9d9b7755
VZ
1258
1259 Refresh(TRUE, &rect);
2ef31e80
VZ
1260}
1261
37df1f33
VZ
1262void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, const wxDateTime& todate, wxPen* pPen, wxBrush* pBrush)
1263{
1264 // Highlights the given range using pen and brush
1265 // Does nothing if todate < fromdate
1266
1267
1268#if DEBUG_PAINT
1269 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate.Format("%d %m %Y"), todate.Format("%d %m %Y"));
1270#endif
1271
1272 if ( todate >= fromdate )
1273 {
1274 // do stuff
1275 // date-coordinates
1bcf0c7d 1276 int fd, fw;
37df1f33
VZ
1277 int td, tw;
1278
1279 // implicit: both dates must be currently shown - checked by GetDateCoord
1280 if ( GetDateCoord(fromdate, &fd, &fw) && GetDateCoord(todate, &td, &tw) )
1281 {
1282#if DEBUG_PAINT
1283 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd, fw, td, tw);
1284#endif
1285 if ( ( (tw - fw) == 1 ) && ( td < fd ) )
1286 {
1287 // special case: interval 7 days or less not in same week
1288 // split in two seperate intervals
1289 wxDateTime tfd = fromdate + wxDateSpan::Days(7-fd);
1290 wxDateTime ftd = tfd + wxDateSpan::Day();
1291#if DEBUG_PAINT
1292 wxLogDebug("Highlight: Seperate segments");
1293#endif
1294 // draw seperately
1295 HighlightRange(pDC, fromdate, tfd, pPen, pBrush);
1296 HighlightRange(pDC, ftd, todate, pPen, pBrush);
1297 }
1298 else
1299 {
1300 int numpoints;
1301 wxPoint corners[8]; // potentially 8 corners in polygon
1302
1303 if ( fw == tw )
1304 {
1305 // simple case: same week
1306 numpoints = 4;
1307 corners[0] = wxPoint((fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset);
1308 corners[1] = wxPoint((fd - 1) * m_widthCol, ((fw + 1 ) * m_heightRow) + m_rowOffset);
1309 corners[2] = wxPoint(td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset);
1310 corners[3] = wxPoint(td * m_widthCol, (tw * m_heightRow) + m_rowOffset);
1311 }
1312 else
1313 {
1314 int cidx = 0;
1315 // "complex" polygon
1316 corners[cidx] = wxPoint((fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++;
1bcf0c7d 1317
37df1f33
VZ
1318 if ( fd > 1 )
1319 {
1320 corners[cidx] = wxPoint((fd - 1) * m_widthCol, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++;
1321 corners[cidx] = wxPoint(0, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++;
1322 }
1323
1324 corners[cidx] = wxPoint(0, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++;
1325 corners[cidx] = wxPoint(td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++;
1326
1327 if ( td < 7 )
1328 {
1329 corners[cidx] = wxPoint(td * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++;
1330 corners[cidx] = wxPoint(7 * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++;
1331 }
1332
1333 corners[cidx] = wxPoint(7 * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++;
1bcf0c7d 1334
37df1f33
VZ
1335 numpoints = cidx;
1336 }
1337
1338 // draw the polygon
1339 pDC->SetBrush(*pBrush);
1340 pDC->SetPen(*pPen);
1341 pDC->DrawPolygon(numpoints, corners);
1342 }
1343 }
1344 }
1345 // else do nothing
1346#if DEBUG_PAINT
1347 wxLogDebug("--- HighlightRange ---");
1348#endif
1349}
1350
1351bool wxCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *week) const
1352{
1bcf0c7d 1353 bool retval = TRUE;
37df1f33
VZ
1354
1355#if DEBUG_PAINT
1356 wxLogDebug("+++ GetDateCoord: (%s) +++", date.Format("%d %m %Y"));
1357#endif
1358
1359 if ( IsDateShown(date) )
1360 {
1361 bool startOnMonday = ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) != 0;
1bcf0c7d 1362
37df1f33
VZ
1363 // Find day
1364 *day = date.GetWeekDay();
1bcf0c7d 1365
37df1f33
VZ
1366 if ( *day == 0 ) // sunday
1367 {
1368 *day = ( startOnMonday ) ? 7 : 1;
1369 }
1370 else
1371 {
999836aa 1372 *day += ( startOnMonday ) ? 0 : 1;
37df1f33
VZ
1373 }
1374
1375 int targetmonth = date.GetMonth() + (12 * date.GetYear());
1376 int thismonth = m_date.GetMonth() + (12 * m_date.GetYear());
1377
1378 // Find week
1379 if ( targetmonth == thismonth )
1380 {
1381 *week = GetWeek(date);
1382 }
1383 else
1384 {
1385 if ( targetmonth < thismonth )
1386 {
1387 *week = 1; // trivial
1388 }
1389 else // targetmonth > thismonth
1390 {
1391 wxDateTime ldcm;
1392 int lastweek;
1393 int lastday;
1394
1395 // get the datecoord of the last day in the month currently shown
1396#if DEBUG_PAINT
1397 wxLogDebug(" +++ LDOM +++");
1398#endif
1399 GetDateCoord(ldcm.SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear()), &lastday, &lastweek);
1400#if DEBUG_PAINT
1401 wxLogDebug(" --- LDOM ---");
1402#endif
1403
1404 wxTimeSpan span = date - ldcm;
1405
1406 int daysfromlast = span.GetDays();
1407#if DEBUG_PAINT
1408 wxLogDebug("daysfromlast: %i", daysfromlast);
1409#endif
1410 if ( daysfromlast + lastday > 7 ) // past week boundary
1411 {
1412 int wholeweeks = (daysfromlast / 7);
1413 *week = wholeweeks + lastweek;
1414 if ( (daysfromlast - (7 * wholeweeks) + lastday) > 7 )
1415 {
1416 *week += 1;
1417 }
1418 }
1419 else
1420 {
1421 *week = lastweek;
1422 }
1423 }
1424 }
1425 }
1426 else
1427 {
1428 *day = -1;
1429 *week = -1;
1bcf0c7d 1430 retval = FALSE;
37df1f33
VZ
1431 }
1432
1433#if DEBUG_PAINT
1434 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date.Format("%d %m %Y"), *day, *week);
1435#endif
1436
1437 return retval;
1438}
1439
2ef31e80
VZ
1440// ----------------------------------------------------------------------------
1441// mouse handling
1442// ----------------------------------------------------------------------------
1443
0185cd09 1444void wxCalendarCtrl::OnDClick(wxMouseEvent& event)
2ef31e80 1445{
0185cd09 1446 if ( HitTest(event.GetPosition()) != wxCAL_HITTEST_DAY )
2ef31e80
VZ
1447 {
1448 event.Skip();
1449 }
1450 else
1451 {
4f6aed9c 1452 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
0185cd09
VZ
1453 }
1454}
1455
1456void wxCalendarCtrl::OnClick(wxMouseEvent& event)
1457{
1458 wxDateTime date;
1459 wxDateTime::WeekDay wday;
1460 switch ( HitTest(event.GetPosition(), &date, &wday) )
1461 {
1462 case wxCAL_HITTEST_DAY:
37df1f33
VZ
1463 if ( IsDateInRange(date) )
1464 {
1465 ChangeDay(date);
2ef31e80 1466
37df1f33
VZ
1467 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED,
1468 wxEVT_CALENDAR_SEL_CHANGED);
1469 }
0185cd09
VZ
1470 break;
1471
1472 case wxCAL_HITTEST_HEADER:
1473 {
1474 wxCalendarEvent event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED);
1475 event.m_wday = wday;
1476 (void)GetEventHandler()->ProcessEvent(event);
1477 }
1478 break;
1479
37df1f33
VZ
1480 case wxCAL_HITTEST_DECMONTH:
1481 case wxCAL_HITTEST_INCMONTH:
1482 case wxCAL_HITTEST_SURROUNDING_WEEK:
1483 SetDateAndNotify(date); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1484 break;
1485
0185cd09
VZ
1486 default:
1487 wxFAIL_MSG(_T("unknown hittest code"));
1488 // fall through
1489
1490 case wxCAL_HITTEST_NOWHERE:
1491 event.Skip();
1492 break;
2ef31e80
VZ
1493 }
1494}
1495
0185cd09
VZ
1496wxCalendarHitTestResult wxCalendarCtrl::HitTest(const wxPoint& pos,
1497 wxDateTime *date,
1498 wxDateTime::WeekDay *wd)
2ef31e80 1499{
9d9b7755
VZ
1500 RecalcGeometry();
1501
2ef31e80 1502 wxCoord y = pos.y;
37df1f33
VZ
1503
1504///////////////////////////////////////////////////////////////////////////////////////////////////////
1505 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
0185cd09 1506 {
37df1f33 1507 // Header: month
1bcf0c7d 1508
37df1f33
VZ
1509 // we need to find out if the hit is on left arrow, on month or on right arrow
1510 // left arrow?
1511 if ( wxRegion(m_leftArrowRect).Contains(pos) == wxInRegion )
0185cd09 1512 {
37df1f33 1513 if ( date )
0185cd09 1514 {
37df1f33
VZ
1515 if ( IsDateInRange(m_date - wxDateSpan::Month()) )
1516 {
1517 *date = m_date - wxDateSpan::Month();
1518 }
1519 else
1520 {
1521 *date = GetLowerDateLimit();
1522 }
1523 }
1524
1525 return wxCAL_HITTEST_DECMONTH;
1526 }
1527
1528 if ( wxRegion(m_rightArrowRect).Contains(pos) == wxInRegion )
1529 {
1530 if ( date )
1531 {
1532 if ( IsDateInRange(m_date + wxDateSpan::Month()) )
1533 {
1534 *date = m_date + wxDateSpan::Month();
1535 }
1536 else
1537 {
1538 *date = GetUpperDateLimit();
1539 }
0185cd09
VZ
1540 }
1541
37df1f33 1542 return wxCAL_HITTEST_INCMONTH;
0185cd09 1543 }
2ef31e80 1544
0185cd09 1545 }
2ef31e80 1546
37df1f33
VZ
1547///////////////////////////////////////////////////////////////////////////////////////////////////////
1548 // Header: Days
1549 int wday = pos.x / m_widthCol;
1550// if ( y < m_heightRow )
1551 if ( y < (m_heightRow + m_rowOffset) )
1552 {
1553 if ( y > m_rowOffset )
1554 {
1555 if ( wd )
1556 {
1557 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST )
1558 {
1559 wday = wday == 6 ? 0 : wday + 1;
1560 }
1561
1562 *wd = (wxDateTime::WeekDay)wday;
1563 }
1564
1565 return wxCAL_HITTEST_HEADER;
1566 }
1567 else
1568 {
1569 return wxCAL_HITTEST_NOWHERE;
1570 }
1571 }
1572
1573// int week = (y - m_heightRow) / m_heightRow;
1574 int week = (y - (m_heightRow + m_rowOffset)) / m_heightRow;
2ef31e80 1575 if ( week >= 6 || wday >= 7 )
0185cd09
VZ
1576 {
1577 return wxCAL_HITTEST_NOWHERE;
1578 }
2ef31e80 1579
0185cd09 1580 wxDateTime dt = GetStartDate() + wxDateSpan::Days(7*week + wday);
2ef31e80 1581
0185cd09
VZ
1582 if ( IsDateShown(dt) )
1583 {
1584 if ( date )
1585 *date = dt;
9d9b7755 1586
37df1f33
VZ
1587 if ( dt.GetMonth() == m_date.GetMonth() )
1588 {
1589
1590 return wxCAL_HITTEST_DAY;
1591 }
1592 else
1593 {
1594 return wxCAL_HITTEST_SURROUNDING_WEEK;
1595 }
0185cd09
VZ
1596 }
1597 else
1598 {
1599 return wxCAL_HITTEST_NOWHERE;
1600 }
2ef31e80 1601}
9d9b7755
VZ
1602
1603// ----------------------------------------------------------------------------
1604// subcontrols events handling
1605// ----------------------------------------------------------------------------
1606
1607void wxCalendarCtrl::OnMonthChange(wxCommandEvent& event)
1608{
1609 wxDateTime::Tm tm = m_date.GetTm();
1610
1611 wxDateTime::Month mon = (wxDateTime::Month)event.GetInt();
1612 if ( tm.mday > wxDateTime::GetNumberOfDays(mon, tm.year) )
1613 {
1614 tm.mday = wxDateTime::GetNumberOfDays(mon, tm.year);
1615 }
1616
37df1f33
VZ
1617 wxDateTime target = wxDateTime(tm.mday, mon, tm.year);
1618
1619 ChangeMonth(&target);
1620 SetDateAndNotify(target);
9d9b7755
VZ
1621}
1622
f0d5e7a2 1623void wxCalendarCtrl::OnYearChange(wxCommandEvent& event)
9d9b7755 1624{
f0d5e7a2
VZ
1625 int year = (int)event.GetInt();
1626 if ( year == INT_MIN )
1627 {
1628 // invalid year in the spin control, ignore it
1629 return;
1630 }
1631
9d9b7755
VZ
1632 wxDateTime::Tm tm = m_date.GetTm();
1633
9d9b7755
VZ
1634 if ( tm.mday > wxDateTime::GetNumberOfDays(tm.mon, year) )
1635 {
1636 tm.mday = wxDateTime::GetNumberOfDays(tm.mon, year);
1637 }
1bcf0c7d 1638
37df1f33
VZ
1639 wxDateTime target = wxDateTime(tm.mday, tm.mon, year);
1640
1641 if ( ChangeYear(&target) )
1642 {
1643 SetDateAndNotify(target);
1644 }
1645 else
1646 {
1647 // In this case we don't want to change the date. That would put us
1648 // inside the same year but a strange number of months forward/back..
1649 m_spinYear->SetValue(target.GetYear());
1650 }
9d9b7755
VZ
1651}
1652
1653// ----------------------------------------------------------------------------
1654// keyboard interface
1655// ----------------------------------------------------------------------------
1656
1657void wxCalendarCtrl::OnChar(wxKeyEvent& event)
1658{
37df1f33 1659 wxDateTime target;
12a3f227 1660 switch ( event.GetKeyCode() )
9d9b7755
VZ
1661 {
1662 case _T('+'):
1663 case WXK_ADD:
37df1f33
VZ
1664 target = m_date + wxDateSpan::Year();
1665 if ( ChangeYear(&target) )
1666 {
1667 SetDateAndNotify(target);
1668 }
9d9b7755
VZ
1669 break;
1670
1671 case _T('-'):
1672 case WXK_SUBTRACT:
37df1f33
VZ
1673 target = m_date - wxDateSpan::Year();
1674 if ( ChangeYear(&target) )
1675 {
1676 SetDateAndNotify(target);
1677 }
9d9b7755
VZ
1678 break;
1679
882a8f40 1680 case WXK_PRIOR:
37df1f33
VZ
1681 target = m_date - wxDateSpan::Month();
1682 ChangeMonth(&target);
1683 SetDateAndNotify(target); // always
9d9b7755
VZ
1684 break;
1685
882a8f40 1686 case WXK_NEXT:
37df1f33
VZ
1687 target = m_date + wxDateSpan::Month();
1688 ChangeMonth(&target);
1689 SetDateAndNotify(target); // always
9d9b7755
VZ
1690 break;
1691
1692 case WXK_RIGHT:
1a8557b1 1693 if ( event.ControlDown() )
37df1f33
VZ
1694 {
1695 target = wxDateTime(m_date).SetToNextWeekDay(
1a8557b1 1696 GetWindowStyle() & wxCAL_MONDAY_FIRST
37df1f33
VZ
1697 ? wxDateTime::Sun : wxDateTime::Sat);
1698 if ( !IsDateInRange(target) )
1699 {
1700 target = GetUpperDateLimit();
1701 }
1702 SetDateAndNotify(target);
1703 }
1a8557b1
VZ
1704 else
1705 SetDateAndNotify(m_date + wxDateSpan::Day());
9d9b7755
VZ
1706 break;
1707
1708 case WXK_LEFT:
1a8557b1 1709 if ( event.ControlDown() )
37df1f33
VZ
1710 {
1711 target = wxDateTime(m_date).SetToPrevWeekDay(
1a8557b1 1712 GetWindowStyle() & wxCAL_MONDAY_FIRST
37df1f33
VZ
1713 ? wxDateTime::Mon : wxDateTime::Sun);
1714 if ( !IsDateInRange(target) )
1715 {
1716 target = GetLowerDateLimit();
1717 }
1718 SetDateAndNotify(target);
1719 }
1a8557b1
VZ
1720 else
1721 SetDateAndNotify(m_date - wxDateSpan::Day());
9d9b7755
VZ
1722 break;
1723
1724 case WXK_UP:
1725 SetDateAndNotify(m_date - wxDateSpan::Week());
1726 break;
1727
1728 case WXK_DOWN:
1729 SetDateAndNotify(m_date + wxDateSpan::Week());
1730 break;
1731
1732 case WXK_HOME:
1a8557b1
VZ
1733 if ( event.ControlDown() )
1734 SetDateAndNotify(wxDateTime::Today());
1735 else
1736 SetDateAndNotify(wxDateTime(1, m_date.GetMonth(), m_date.GetYear()));
1737 break;
1738
1739 case WXK_END:
1740 SetDateAndNotify(wxDateTime(m_date).SetToLastMonthDay());
9d9b7755
VZ
1741 break;
1742
4f6aed9c
VZ
1743 case WXK_RETURN:
1744 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
1745 break;
1746
9d9b7755
VZ
1747 default:
1748 event.Skip();
1749 }
1750}
1751
1752// ----------------------------------------------------------------------------
4f6aed9c 1753// holidays handling
9d9b7755
VZ
1754// ----------------------------------------------------------------------------
1755
4f6aed9c 1756void wxCalendarCtrl::EnableHolidayDisplay(bool display)
9d9b7755 1757{
4f6aed9c
VZ
1758 long style = GetWindowStyle();
1759 if ( display )
1760 style |= wxCAL_SHOW_HOLIDAYS;
1761 else
1762 style &= ~wxCAL_SHOW_HOLIDAYS;
1763
1764 SetWindowStyle(style);
1765
1766 if ( display )
1767 SetHolidayAttrs();
1768 else
1769 ResetHolidayAttrs();
1770
1771 Refresh();
1772}
1773
1774void wxCalendarCtrl::SetHolidayAttrs()
1775{
1776 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS )
1777 {
1778 ResetHolidayAttrs();
1779
1780 wxDateTime::Tm tm = m_date.GetTm();
1781 wxDateTime dtStart(1, tm.mon, tm.year),
1782 dtEnd = dtStart.GetLastMonthDay();
1783
1784 wxDateTimeArray hol;
1785 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart, dtEnd, hol);
1786
1787 size_t count = hol.GetCount();
1788 for ( size_t n = 0; n < count; n++ )
1789 {
1790 SetHoliday(hol[n].GetDay());
1791 }
1792 }
1793}
1794
1795void wxCalendarCtrl::SetHoliday(size_t day)
1796{
1797 wxCHECK_RET( day > 0 && day < 32, _T("invalid day in SetHoliday") );
0185cd09 1798
4f6aed9c
VZ
1799 wxCalendarDateAttr *attr = GetAttr(day);
1800 if ( !attr )
0185cd09 1801 {
4f6aed9c
VZ
1802 attr = new wxCalendarDateAttr;
1803 }
0185cd09 1804
4f6aed9c
VZ
1805 attr->SetHoliday(TRUE);
1806
1807 // can't use SetAttr() because it would delete this pointer
1808 m_attrs[day - 1] = attr;
1809}
1810
1811void wxCalendarCtrl::ResetHolidayAttrs()
1812{
1813 for ( size_t day = 0; day < 31; day++ )
1814 {
1815 if ( m_attrs[day] )
1816 {
1817 m_attrs[day]->SetHoliday(FALSE);
1818 }
0185cd09
VZ
1819 }
1820}
1821
4f6aed9c
VZ
1822// ----------------------------------------------------------------------------
1823// wxCalendarEvent
1824// ----------------------------------------------------------------------------
1825
0185cd09
VZ
1826void wxCalendarEvent::Init()
1827{
1828 m_wday = wxDateTime::Inv_WeekDay;
9d9b7755
VZ
1829}
1830
1831wxCalendarEvent::wxCalendarEvent(wxCalendarCtrl *cal, wxEventType type)
1832 : wxCommandEvent(type, cal->GetId())
1833{
1834 m_date = cal->GetDate();
4fa54a31 1835 SetEventObject(cal);
9d9b7755 1836}
2fa7c206 1837
1e6feb95 1838#endif // wxUSE_CALENDARCTRL
2fa7c206 1839