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