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