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