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