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