]> git.saurik.com Git - wxWidgets.git/blame - src/generic/calctrl.cpp
Blind fix for bug [ 1106890 ] (undeclared symbols on Solaris).
[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());
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);
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
978 rightarrow[0] = wxPoint(0, 0);
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;
987 m_leftArrowRect = wxRect(0, 0, 0, 0);
988 m_rightArrowRect = wxRect(0, 0, 0, 0);
989
990 if ( AllowMonthChange() )
991 {
992 wxDateTime ldpm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) - wxDateSpan::Day(); // last day prev month
993 // Check if range permits change
ca65c044 994 if ( IsDateInRange(ldpm) && ( ( ldpm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) )
37df1f33
VZ
995 {
996 m_leftArrowRect = wxRect(larrowx - 3, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6));
997 dc.SetBrush(wxBrush(*wxBLACK, wxSOLID));
998 dc.SetPen(wxPen(*wxBLACK, 1, wxSOLID));
999 dc.DrawPolygon(3, leftarrow, larrowx , arrowy, wxWINDING_RULE);
1000 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1001 dc.DrawRectangle(m_leftArrowRect);
1002 }
1003 wxDateTime fdnm = wxDateTime(1,m_date.GetMonth(), m_date.GetYear()) + wxDateSpan::Month(); // first day next month
ca65c044 1004 if ( IsDateInRange(fdnm) && ( ( fdnm.GetYear() == m_date.GetYear() ) ? true : AllowYearChange() ) )
37df1f33
VZ
1005 {
1006 m_rightArrowRect = wxRect(rarrowx - 4, arrowy - 3, (arrowheight / 2) + 8, (arrowheight + 6));
1007 dc.SetBrush(wxBrush(*wxBLACK, wxSOLID));
1008 dc.SetPen(wxPen(*wxBLACK, 1, wxSOLID));
1009 dc.DrawPolygon(3, rightarrow, rarrowx , arrowy, wxWINDING_RULE);
1010 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1011 dc.DrawRectangle(m_rightArrowRect);
1012 }
1013 }
1014
1015 y += m_heightRow;
1016 }
1017
2ef31e80 1018 // first draw the week days
37df1f33 1019 if ( IsExposed(0, y, 7*m_widthCol, m_heightRow) )
2ef31e80 1020 {
882a8f40 1021#if DEBUG_PAINT
f6bcfd97 1022 wxLogDebug("painting the header");
882a8f40 1023#endif
9d9b7755 1024
9d9b7755 1025 dc.SetBackgroundMode(wxTRANSPARENT);
4f6aed9c
VZ
1026 dc.SetTextForeground(m_colHeaderFg);
1027 dc.SetBrush(wxBrush(m_colHeaderBg, wxSOLID));
1028 dc.SetPen(wxPen(m_colHeaderBg, 1, wxSOLID));
bb61a983 1029 dc.DrawRectangle(0, y, GetClientSize().x, m_heightRow);
1a8557b1
VZ
1030
1031 bool startOnMonday = (GetWindowStyle() & wxCAL_MONDAY_FIRST) != 0;
1032 for ( size_t wd = 0; wd < 7; wd++ )
9d9b7755 1033 {
1a8557b1
VZ
1034 size_t n;
1035 if ( startOnMonday )
1036 n = wd == 6 ? 0 : wd + 1;
1037 else
1038 n = wd;
37df1f33
VZ
1039 wxCoord dayw, dayh;
1040 dc.GetTextExtent(m_weekdays[n], &dayw, &dayh);
37df1f33 1041 dc.DrawText(m_weekdays[n], (wd*m_widthCol) + ((m_widthCol- dayw) / 2), y); // center the day-name
9d9b7755 1042 }
2ef31e80
VZ
1043 }
1044
1045 // then the calendar itself
1046 dc.SetTextForeground(*wxBLACK);
1047 //dc.SetFont(*wxNORMAL_FONT);
1048
37df1f33 1049 y += m_heightRow;
2ef31e80 1050 wxDateTime date = GetStartDate();
37df1f33 1051
882a8f40 1052#if DEBUG_PAINT
f6bcfd97 1053 wxLogDebug("starting calendar from %s\n",
9d9b7755 1054 date.Format("%a %d-%m-%Y %H:%M:%S").c_str());
882a8f40 1055#endif
9d9b7755 1056
2ef31e80 1057 dc.SetBackgroundMode(wxSOLID);
9d9b7755 1058 for ( size_t nWeek = 1; nWeek <= 6; nWeek++, y += m_heightRow )
2ef31e80 1059 {
9d9b7755 1060 // if the update region doesn't intersect this row, don't paint it
15807266 1061 if ( !IsExposed(0, y, 7*m_widthCol, m_heightRow - 1) )
9d9b7755
VZ
1062 {
1063 date += wxDateSpan::Week();
1064
1065 continue;
1066 }
882a8f40 1067
1a8557b1 1068#if DEBUG_PAINT
f6bcfd97 1069 wxLogDebug("painting week %d at y = %d\n", nWeek, y);
882a8f40 1070#endif
9d9b7755 1071
1a8557b1 1072 for ( size_t wd = 0; wd < 7; wd++ )
2ef31e80
VZ
1073 {
1074 if ( IsDateShown(date) )
1075 {
882a8f40 1076 // don't use wxDate::Format() which prepends 0s
4f6aed9c
VZ
1077 unsigned int day = date.GetDay();
1078 wxString dayStr = wxString::Format(_T("%u"), day);
3965571c 1079 wxCoord width;
4f6aed9c
VZ
1080 dc.GetTextExtent(dayStr, &width, (wxCoord *)NULL);
1081
ca65c044
WS
1082 bool changedColours = false,
1083 changedFont = false;
4f6aed9c 1084
ca65c044 1085 bool isSel = false;
37df1f33 1086 wxCalendarDateAttr *attr = NULL;
2ef31e80 1087
37df1f33 1088 if ( date.GetMonth() != m_date.GetMonth() || !IsDateInRange(date) )
2ef31e80 1089 {
37df1f33
VZ
1090 // surrounding week or out-of-range
1091 // draw "disabled"
1092 dc.SetTextForeground(*wxLIGHT_GREY);
ca65c044 1093 changedColours = true;
4f6aed9c 1094 }
37df1f33 1095 else
4f6aed9c 1096 {
37df1f33
VZ
1097 isSel = date.IsSameDate(m_date);
1098 attr = m_attrs[day - 1];
4f6aed9c 1099
37df1f33 1100 if ( isSel )
4f6aed9c 1101 {
37df1f33
VZ
1102 dc.SetTextForeground(m_colHighlightFg);
1103 dc.SetTextBackground(m_colHighlightBg);
4f6aed9c 1104
ca65c044 1105 changedColours = true;
4f6aed9c 1106 }
37df1f33 1107 else if ( attr )
4f6aed9c 1108 {
37df1f33
VZ
1109 wxColour colFg, colBg;
1110
1111 if ( attr->IsHoliday() )
1112 {
1113 colFg = m_colHolidayFg;
1114 colBg = m_colHolidayBg;
1115 }
1116 else
1117 {
1118 colFg = attr->GetTextColour();
1119 colBg = attr->GetBackgroundColour();
1120 }
1121
1122 if ( colFg.Ok() )
1123 {
1124 dc.SetTextForeground(colFg);
ca65c044 1125 changedColours = true;
37df1f33
VZ
1126 }
1127
1128 if ( colBg.Ok() )
1129 {
1130 dc.SetTextBackground(colBg);
ca65c044 1131 changedColours = true;
37df1f33
VZ
1132 }
1133
1134 if ( attr->HasFont() )
1135 {
1136 dc.SetFont(attr->GetFont());
ca65c044 1137 changedFont = true;
37df1f33 1138 }
4f6aed9c 1139 }
2ef31e80
VZ
1140 }
1141
4f6aed9c
VZ
1142 wxCoord x = wd*m_widthCol + (m_widthCol - width) / 2;
1143 dc.DrawText(dayStr, x, y + 1);
2ef31e80 1144
4f6aed9c
VZ
1145 if ( !isSel && attr && attr->HasBorder() )
1146 {
1147 wxColour colBorder;
1148 if ( attr->HasBorderColour() )
1149 {
1150 colBorder = attr->GetBorderColour();
1151 }
1152 else
1153 {
ab473127 1154 colBorder = GetForegroundColour();
4f6aed9c
VZ
1155 }
1156
1157 wxPen pen(colBorder, 1, wxSOLID);
1158 dc.SetPen(pen);
1159 dc.SetBrush(*wxTRANSPARENT_BRUSH);
1160
1161 switch ( attr->GetBorder() )
1162 {
1163 case wxCAL_BORDER_SQUARE:
1164 dc.DrawRectangle(x - 2, y,
1165 width + 4, m_heightRow);
1166 break;
1167
1168 case wxCAL_BORDER_ROUND:
1169 dc.DrawEllipse(x - 2, y,
1170 width + 4, m_heightRow);
1171 break;
1172
1173 default:
1174 wxFAIL_MSG(_T("unknown border type"));
1175 }
1176 }
1177
1178 if ( changedColours )
2ef31e80 1179 {
ab473127
RD
1180 dc.SetTextForeground(GetForegroundColour());
1181 dc.SetTextBackground(GetBackgroundColour());
2ef31e80 1182 }
4f6aed9c
VZ
1183
1184 if ( changedFont )
1185 {
ab473127 1186 dc.SetFont(GetFont());
4f6aed9c 1187 }
2ef31e80
VZ
1188 }
1189 //else: just don't draw it
1190
1191 date += wxDateSpan::Day();
1192 }
2ef31e80 1193 }
37df1f33
VZ
1194
1195 // Greying out out-of-range background
1196 bool showSurrounding = (GetWindowStyle() & wxCAL_SHOW_SURROUNDING_WEEKS) != 0;
1197
1198 date = ( showSurrounding ) ? GetStartDate() : wxDateTime(1, m_date.GetMonth(), m_date.GetYear());
1199 if ( !IsDateInRange(date) )
1200 {
1201 wxDateTime firstOOR = GetLowerDateLimit() - wxDateSpan::Day(); // first out-of-range
1202
1203 wxBrush oorbrush = *wxLIGHT_GREY_BRUSH;
1204 oorbrush.SetStyle(wxFDIAGONAL_HATCH);
1205
1206 HighlightRange(&dc, date, firstOOR, wxTRANSPARENT_PEN, &oorbrush);
1207 }
1208
1209 date = ( showSurrounding ) ? GetStartDate() + wxDateSpan::Weeks(6) - wxDateSpan::Day() : wxDateTime().SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear());
1210 if ( !IsDateInRange(date) )
1211 {
1212 wxDateTime firstOOR = GetUpperDateLimit() + wxDateSpan::Day(); // first out-of-range
1bcf0c7d 1213
37df1f33
VZ
1214 wxBrush oorbrush = *wxLIGHT_GREY_BRUSH;
1215 oorbrush.SetStyle(wxFDIAGONAL_HATCH);
1216
1217 HighlightRange(&dc, firstOOR, date, wxTRANSPARENT_PEN, &oorbrush);
1218 }
1219
882a8f40 1220#if DEBUG_PAINT
f6bcfd97 1221 wxLogDebug("+++ finished painting");
882a8f40 1222#endif
9d9b7755
VZ
1223}
1224
1225void wxCalendarCtrl::RefreshDate(const wxDateTime& date)
1226{
1227 RecalcGeometry();
1228
1229 wxRect rect;
1230
1231 // always refresh the whole row at once because our OnPaint() will draw
1232 // the whole row anyhow - and this allows the small optimisation in
1233 // OnClick() below to work
1234 rect.x = 0;
37df1f33
VZ
1235
1236 rect.y = (m_heightRow * GetWeek(date)) + m_rowOffset;
1237
9d9b7755
VZ
1238 rect.width = 7*m_widthCol;
1239 rect.height = m_heightRow;
1240
f6bcfd97
BP
1241#ifdef __WXMSW__
1242 // VZ: for some reason, the selected date seems to occupy more space under
1243 // MSW - this is probably some bug in the font size calculations, but I
1244 // don't know where exactly. This fix is ugly and leads to more
1245 // refreshes than really needed, but without it the selected days
1246 // leaves even more ugly underscores on screen.
1247 rect.Inflate(0, 1);
1248#endif // MSW
1249
882a8f40 1250#if DEBUG_PAINT
f6bcfd97 1251 wxLogDebug("*** refreshing week %d at (%d, %d)-(%d, %d)\n",
9d9b7755
VZ
1252 GetWeek(date),
1253 rect.x, rect.y,
1254 rect.x + rect.width, rect.y + rect.height);
882a8f40 1255#endif
9d9b7755 1256
ca65c044 1257 Refresh(true, &rect);
2ef31e80
VZ
1258}
1259
37df1f33
VZ
1260void wxCalendarCtrl::HighlightRange(wxPaintDC* pDC, const wxDateTime& fromdate, const wxDateTime& todate, wxPen* pPen, wxBrush* pBrush)
1261{
1262 // Highlights the given range using pen and brush
1263 // Does nothing if todate < fromdate
1264
1265
1266#if DEBUG_PAINT
1267 wxLogDebug("+++ HighlightRange: (%s) - (%s) +++", fromdate.Format("%d %m %Y"), todate.Format("%d %m %Y"));
1268#endif
1269
1270 if ( todate >= fromdate )
1271 {
1272 // do stuff
1273 // date-coordinates
1bcf0c7d 1274 int fd, fw;
37df1f33
VZ
1275 int td, tw;
1276
1277 // implicit: both dates must be currently shown - checked by GetDateCoord
1278 if ( GetDateCoord(fromdate, &fd, &fw) && GetDateCoord(todate, &td, &tw) )
1279 {
1280#if DEBUG_PAINT
1281 wxLogDebug("Highlight range: (%i, %i) - (%i, %i)", fd, fw, td, tw);
1282#endif
1283 if ( ( (tw - fw) == 1 ) && ( td < fd ) )
1284 {
1285 // special case: interval 7 days or less not in same week
1286 // split in two seperate intervals
1287 wxDateTime tfd = fromdate + wxDateSpan::Days(7-fd);
1288 wxDateTime ftd = tfd + wxDateSpan::Day();
1289#if DEBUG_PAINT
1290 wxLogDebug("Highlight: Seperate segments");
1291#endif
1292 // draw seperately
1293 HighlightRange(pDC, fromdate, tfd, pPen, pBrush);
1294 HighlightRange(pDC, ftd, todate, pPen, pBrush);
1295 }
1296 else
1297 {
1298 int numpoints;
1299 wxPoint corners[8]; // potentially 8 corners in polygon
1300
1301 if ( fw == tw )
1302 {
1303 // simple case: same week
1304 numpoints = 4;
1305 corners[0] = wxPoint((fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset);
1306 corners[1] = wxPoint((fd - 1) * m_widthCol, ((fw + 1 ) * m_heightRow) + m_rowOffset);
1307 corners[2] = wxPoint(td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset);
1308 corners[3] = wxPoint(td * m_widthCol, (tw * m_heightRow) + m_rowOffset);
1309 }
1310 else
1311 {
1312 int cidx = 0;
1313 // "complex" polygon
1314 corners[cidx] = wxPoint((fd - 1) * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++;
1bcf0c7d 1315
37df1f33
VZ
1316 if ( fd > 1 )
1317 {
1318 corners[cidx] = wxPoint((fd - 1) * m_widthCol, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++;
1319 corners[cidx] = wxPoint(0, ((fw + 1) * m_heightRow) + m_rowOffset); cidx++;
1320 }
1321
1322 corners[cidx] = wxPoint(0, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++;
1323 corners[cidx] = wxPoint(td * m_widthCol, ((tw + 1) * m_heightRow) + m_rowOffset); cidx++;
1324
1325 if ( td < 7 )
1326 {
1327 corners[cidx] = wxPoint(td * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++;
1328 corners[cidx] = wxPoint(7 * m_widthCol, (tw * m_heightRow) + m_rowOffset); cidx++;
1329 }
1330
1331 corners[cidx] = wxPoint(7 * m_widthCol, (fw * m_heightRow) + m_rowOffset); cidx++;
1bcf0c7d 1332
37df1f33
VZ
1333 numpoints = cidx;
1334 }
1335
1336 // draw the polygon
1337 pDC->SetBrush(*pBrush);
1338 pDC->SetPen(*pPen);
1339 pDC->DrawPolygon(numpoints, corners);
1340 }
1341 }
1342 }
1343 // else do nothing
1344#if DEBUG_PAINT
1345 wxLogDebug("--- HighlightRange ---");
1346#endif
1347}
1348
1349bool wxCalendarCtrl::GetDateCoord(const wxDateTime& date, int *day, int *week) const
1350{
ca65c044 1351 bool retval = true;
37df1f33
VZ
1352
1353#if DEBUG_PAINT
1354 wxLogDebug("+++ GetDateCoord: (%s) +++", date.Format("%d %m %Y"));
1355#endif
1356
1357 if ( IsDateShown(date) )
1358 {
1359 bool startOnMonday = ( GetWindowStyle() & wxCAL_MONDAY_FIRST ) != 0;
1bcf0c7d 1360
37df1f33
VZ
1361 // Find day
1362 *day = date.GetWeekDay();
1bcf0c7d 1363
37df1f33
VZ
1364 if ( *day == 0 ) // sunday
1365 {
1366 *day = ( startOnMonday ) ? 7 : 1;
1367 }
1368 else
1369 {
999836aa 1370 *day += ( startOnMonday ) ? 0 : 1;
37df1f33
VZ
1371 }
1372
1373 int targetmonth = date.GetMonth() + (12 * date.GetYear());
1374 int thismonth = m_date.GetMonth() + (12 * m_date.GetYear());
1375
1376 // Find week
1377 if ( targetmonth == thismonth )
1378 {
1379 *week = GetWeek(date);
1380 }
1381 else
1382 {
1383 if ( targetmonth < thismonth )
1384 {
1385 *week = 1; // trivial
1386 }
1387 else // targetmonth > thismonth
1388 {
1389 wxDateTime ldcm;
1390 int lastweek;
1391 int lastday;
1392
1393 // get the datecoord of the last day in the month currently shown
1394#if DEBUG_PAINT
1395 wxLogDebug(" +++ LDOM +++");
1396#endif
1397 GetDateCoord(ldcm.SetToLastMonthDay(m_date.GetMonth(), m_date.GetYear()), &lastday, &lastweek);
1398#if DEBUG_PAINT
1399 wxLogDebug(" --- LDOM ---");
1400#endif
1401
1402 wxTimeSpan span = date - ldcm;
1403
1404 int daysfromlast = span.GetDays();
1405#if DEBUG_PAINT
1406 wxLogDebug("daysfromlast: %i", daysfromlast);
1407#endif
1408 if ( daysfromlast + lastday > 7 ) // past week boundary
1409 {
1410 int wholeweeks = (daysfromlast / 7);
1411 *week = wholeweeks + lastweek;
1412 if ( (daysfromlast - (7 * wholeweeks) + lastday) > 7 )
1413 {
1414 *week += 1;
1415 }
1416 }
1417 else
1418 {
1419 *week = lastweek;
1420 }
1421 }
1422 }
1423 }
1424 else
1425 {
1426 *day = -1;
1427 *week = -1;
ca65c044 1428 retval = false;
37df1f33
VZ
1429 }
1430
1431#if DEBUG_PAINT
1432 wxLogDebug("--- GetDateCoord: (%s) = (%i, %i) ---", date.Format("%d %m %Y"), *day, *week);
1433#endif
1434
1435 return retval;
1436}
1437
2ef31e80
VZ
1438// ----------------------------------------------------------------------------
1439// mouse handling
1440// ----------------------------------------------------------------------------
1441
0185cd09 1442void wxCalendarCtrl::OnDClick(wxMouseEvent& event)
2ef31e80 1443{
0185cd09 1444 if ( HitTest(event.GetPosition()) != wxCAL_HITTEST_DAY )
2ef31e80
VZ
1445 {
1446 event.Skip();
1447 }
1448 else
1449 {
4f6aed9c 1450 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
0185cd09
VZ
1451 }
1452}
1453
1454void wxCalendarCtrl::OnClick(wxMouseEvent& event)
1455{
1456 wxDateTime date;
1457 wxDateTime::WeekDay wday;
1458 switch ( HitTest(event.GetPosition(), &date, &wday) )
1459 {
1460 case wxCAL_HITTEST_DAY:
37df1f33
VZ
1461 if ( IsDateInRange(date) )
1462 {
1463 ChangeDay(date);
2ef31e80 1464
37df1f33
VZ
1465 GenerateEvents(wxEVT_CALENDAR_DAY_CHANGED,
1466 wxEVT_CALENDAR_SEL_CHANGED);
1467 }
0185cd09
VZ
1468 break;
1469
1470 case wxCAL_HITTEST_HEADER:
1471 {
1472 wxCalendarEvent event(this, wxEVT_CALENDAR_WEEKDAY_CLICKED);
1473 event.m_wday = wday;
1474 (void)GetEventHandler()->ProcessEvent(event);
1475 }
1476 break;
1477
37df1f33
VZ
1478 case wxCAL_HITTEST_DECMONTH:
1479 case wxCAL_HITTEST_INCMONTH:
1480 case wxCAL_HITTEST_SURROUNDING_WEEK:
1481 SetDateAndNotify(date); // we probably only want to refresh the control. No notification.. (maybe as an option?)
1482 break;
1483
0185cd09
VZ
1484 default:
1485 wxFAIL_MSG(_T("unknown hittest code"));
1486 // fall through
1487
1488 case wxCAL_HITTEST_NOWHERE:
1489 event.Skip();
1490 break;
2ef31e80
VZ
1491 }
1492}
1493
0185cd09
VZ
1494wxCalendarHitTestResult wxCalendarCtrl::HitTest(const wxPoint& pos,
1495 wxDateTime *date,
1496 wxDateTime::WeekDay *wd)
2ef31e80 1497{
9d9b7755
VZ
1498 RecalcGeometry();
1499
2ef31e80 1500 wxCoord y = pos.y;
37df1f33
VZ
1501
1502///////////////////////////////////////////////////////////////////////////////////////////////////////
1503 if ( (GetWindowStyle() & wxCAL_SEQUENTIAL_MONTH_SELECTION) )
0185cd09 1504 {
37df1f33 1505 // Header: month
1bcf0c7d 1506
37df1f33
VZ
1507 // we need to find out if the hit is on left arrow, on month or on right arrow
1508 // left arrow?
1509 if ( wxRegion(m_leftArrowRect).Contains(pos) == wxInRegion )
0185cd09 1510 {
37df1f33 1511 if ( date )
0185cd09 1512 {
37df1f33
VZ
1513 if ( IsDateInRange(m_date - wxDateSpan::Month()) )
1514 {
1515 *date = m_date - wxDateSpan::Month();
1516 }
1517 else
1518 {
1519 *date = GetLowerDateLimit();
1520 }
1521 }
1522
1523 return wxCAL_HITTEST_DECMONTH;
1524 }
1525
1526 if ( wxRegion(m_rightArrowRect).Contains(pos) == wxInRegion )
1527 {
1528 if ( date )
1529 {
1530 if ( IsDateInRange(m_date + wxDateSpan::Month()) )
1531 {
1532 *date = m_date + wxDateSpan::Month();
1533 }
1534 else
1535 {
1536 *date = GetUpperDateLimit();
1537 }
0185cd09
VZ
1538 }
1539
37df1f33 1540 return wxCAL_HITTEST_INCMONTH;
0185cd09 1541 }
2ef31e80 1542
0185cd09 1543 }
2ef31e80 1544
37df1f33
VZ
1545///////////////////////////////////////////////////////////////////////////////////////////////////////
1546 // Header: Days
1547 int wday = pos.x / m_widthCol;
1548// if ( y < m_heightRow )
1549 if ( y < (m_heightRow + m_rowOffset) )
1550 {
1551 if ( y > m_rowOffset )
1552 {
1553 if ( wd )
1554 {
1555 if ( GetWindowStyle() & wxCAL_MONDAY_FIRST )
1556 {
1557 wday = wday == 6 ? 0 : wday + 1;
1558 }
1559
1560 *wd = (wxDateTime::WeekDay)wday;
1561 }
1562
1563 return wxCAL_HITTEST_HEADER;
1564 }
1565 else
1566 {
1567 return wxCAL_HITTEST_NOWHERE;
1568 }
1569 }
1570
1571// int week = (y - m_heightRow) / m_heightRow;
1572 int week = (y - (m_heightRow + m_rowOffset)) / m_heightRow;
2ef31e80 1573 if ( week >= 6 || wday >= 7 )
0185cd09
VZ
1574 {
1575 return wxCAL_HITTEST_NOWHERE;
1576 }
2ef31e80 1577
0185cd09 1578 wxDateTime dt = GetStartDate() + wxDateSpan::Days(7*week + wday);
2ef31e80 1579
0185cd09
VZ
1580 if ( IsDateShown(dt) )
1581 {
1582 if ( date )
1583 *date = dt;
9d9b7755 1584
37df1f33
VZ
1585 if ( dt.GetMonth() == m_date.GetMonth() )
1586 {
1587
1588 return wxCAL_HITTEST_DAY;
1589 }
1590 else
1591 {
1592 return wxCAL_HITTEST_SURROUNDING_WEEK;
1593 }
0185cd09
VZ
1594 }
1595 else
1596 {
1597 return wxCAL_HITTEST_NOWHERE;
1598 }
2ef31e80 1599}
9d9b7755
VZ
1600
1601// ----------------------------------------------------------------------------
1602// subcontrols events handling
1603// ----------------------------------------------------------------------------
1604
1605void wxCalendarCtrl::OnMonthChange(wxCommandEvent& event)
1606{
1607 wxDateTime::Tm tm = m_date.GetTm();
1608
1609 wxDateTime::Month mon = (wxDateTime::Month)event.GetInt();
1610 if ( tm.mday > wxDateTime::GetNumberOfDays(mon, tm.year) )
1611 {
1612 tm.mday = wxDateTime::GetNumberOfDays(mon, tm.year);
1613 }
1614
37df1f33
VZ
1615 wxDateTime target = wxDateTime(tm.mday, mon, tm.year);
1616
1617 ChangeMonth(&target);
1618 SetDateAndNotify(target);
9d9b7755
VZ
1619}
1620
f0d5e7a2 1621void wxCalendarCtrl::OnYearChange(wxCommandEvent& event)
9d9b7755 1622{
f0d5e7a2
VZ
1623 int year = (int)event.GetInt();
1624 if ( year == INT_MIN )
1625 {
1626 // invalid year in the spin control, ignore it
1627 return;
1628 }
1629
9d9b7755
VZ
1630 wxDateTime::Tm tm = m_date.GetTm();
1631
9d9b7755
VZ
1632 if ( tm.mday > wxDateTime::GetNumberOfDays(tm.mon, year) )
1633 {
1634 tm.mday = wxDateTime::GetNumberOfDays(tm.mon, year);
1635 }
1bcf0c7d 1636
37df1f33
VZ
1637 wxDateTime target = wxDateTime(tm.mday, tm.mon, year);
1638
1639 if ( ChangeYear(&target) )
1640 {
1641 SetDateAndNotify(target);
1642 }
1643 else
1644 {
1645 // In this case we don't want to change the date. That would put us
1646 // inside the same year but a strange number of months forward/back..
1647 m_spinYear->SetValue(target.GetYear());
1648 }
9d9b7755
VZ
1649}
1650
1651// ----------------------------------------------------------------------------
1652// keyboard interface
1653// ----------------------------------------------------------------------------
1654
1655void wxCalendarCtrl::OnChar(wxKeyEvent& event)
1656{
37df1f33 1657 wxDateTime target;
12a3f227 1658 switch ( event.GetKeyCode() )
9d9b7755
VZ
1659 {
1660 case _T('+'):
1661 case WXK_ADD:
37df1f33
VZ
1662 target = m_date + wxDateSpan::Year();
1663 if ( ChangeYear(&target) )
1664 {
1665 SetDateAndNotify(target);
1666 }
9d9b7755
VZ
1667 break;
1668
1669 case _T('-'):
1670 case WXK_SUBTRACT:
37df1f33
VZ
1671 target = m_date - wxDateSpan::Year();
1672 if ( ChangeYear(&target) )
1673 {
1674 SetDateAndNotify(target);
1675 }
9d9b7755
VZ
1676 break;
1677
882a8f40 1678 case WXK_PRIOR:
37df1f33
VZ
1679 target = m_date - wxDateSpan::Month();
1680 ChangeMonth(&target);
1681 SetDateAndNotify(target); // always
9d9b7755
VZ
1682 break;
1683
882a8f40 1684 case WXK_NEXT:
37df1f33
VZ
1685 target = m_date + wxDateSpan::Month();
1686 ChangeMonth(&target);
1687 SetDateAndNotify(target); // always
9d9b7755
VZ
1688 break;
1689
1690 case WXK_RIGHT:
1a8557b1 1691 if ( event.ControlDown() )
37df1f33
VZ
1692 {
1693 target = wxDateTime(m_date).SetToNextWeekDay(
1a8557b1 1694 GetWindowStyle() & wxCAL_MONDAY_FIRST
37df1f33
VZ
1695 ? wxDateTime::Sun : wxDateTime::Sat);
1696 if ( !IsDateInRange(target) )
1697 {
1698 target = GetUpperDateLimit();
1699 }
1700 SetDateAndNotify(target);
1701 }
1a8557b1
VZ
1702 else
1703 SetDateAndNotify(m_date + wxDateSpan::Day());
9d9b7755
VZ
1704 break;
1705
1706 case WXK_LEFT:
1a8557b1 1707 if ( event.ControlDown() )
37df1f33
VZ
1708 {
1709 target = wxDateTime(m_date).SetToPrevWeekDay(
1a8557b1 1710 GetWindowStyle() & wxCAL_MONDAY_FIRST
37df1f33
VZ
1711 ? wxDateTime::Mon : wxDateTime::Sun);
1712 if ( !IsDateInRange(target) )
1713 {
1714 target = GetLowerDateLimit();
1715 }
1716 SetDateAndNotify(target);
1717 }
1a8557b1
VZ
1718 else
1719 SetDateAndNotify(m_date - wxDateSpan::Day());
9d9b7755
VZ
1720 break;
1721
1722 case WXK_UP:
1723 SetDateAndNotify(m_date - wxDateSpan::Week());
1724 break;
1725
1726 case WXK_DOWN:
1727 SetDateAndNotify(m_date + wxDateSpan::Week());
1728 break;
1729
1730 case WXK_HOME:
1a8557b1
VZ
1731 if ( event.ControlDown() )
1732 SetDateAndNotify(wxDateTime::Today());
1733 else
1734 SetDateAndNotify(wxDateTime(1, m_date.GetMonth(), m_date.GetYear()));
1735 break;
1736
1737 case WXK_END:
1738 SetDateAndNotify(wxDateTime(m_date).SetToLastMonthDay());
9d9b7755
VZ
1739 break;
1740
4f6aed9c
VZ
1741 case WXK_RETURN:
1742 GenerateEvent(wxEVT_CALENDAR_DOUBLECLICKED);
1743 break;
1744
9d9b7755
VZ
1745 default:
1746 event.Skip();
1747 }
1748}
1749
1750// ----------------------------------------------------------------------------
4f6aed9c 1751// holidays handling
9d9b7755
VZ
1752// ----------------------------------------------------------------------------
1753
4f6aed9c 1754void wxCalendarCtrl::EnableHolidayDisplay(bool display)
9d9b7755 1755{
4f6aed9c
VZ
1756 long style = GetWindowStyle();
1757 if ( display )
1758 style |= wxCAL_SHOW_HOLIDAYS;
1759 else
1760 style &= ~wxCAL_SHOW_HOLIDAYS;
1761
1762 SetWindowStyle(style);
1763
1764 if ( display )
1765 SetHolidayAttrs();
1766 else
1767 ResetHolidayAttrs();
1768
1769 Refresh();
1770}
1771
1772void wxCalendarCtrl::SetHolidayAttrs()
1773{
1774 if ( GetWindowStyle() & wxCAL_SHOW_HOLIDAYS )
1775 {
1776 ResetHolidayAttrs();
1777
1778 wxDateTime::Tm tm = m_date.GetTm();
1779 wxDateTime dtStart(1, tm.mon, tm.year),
1780 dtEnd = dtStart.GetLastMonthDay();
1781
1782 wxDateTimeArray hol;
1783 wxDateTimeHolidayAuthority::GetHolidaysInRange(dtStart, dtEnd, hol);
1784
1785 size_t count = hol.GetCount();
1786 for ( size_t n = 0; n < count; n++ )
1787 {
1788 SetHoliday(hol[n].GetDay());
1789 }
1790 }
1791}
1792
1793void wxCalendarCtrl::SetHoliday(size_t day)
1794{
1795 wxCHECK_RET( day > 0 && day < 32, _T("invalid day in SetHoliday") );
0185cd09 1796
4f6aed9c
VZ
1797 wxCalendarDateAttr *attr = GetAttr(day);
1798 if ( !attr )
0185cd09 1799 {
4f6aed9c
VZ
1800 attr = new wxCalendarDateAttr;
1801 }
0185cd09 1802
ca65c044 1803 attr->SetHoliday(true);
4f6aed9c
VZ
1804
1805 // can't use SetAttr() because it would delete this pointer
1806 m_attrs[day - 1] = attr;
1807}
1808
1809void wxCalendarCtrl::ResetHolidayAttrs()
1810{
1811 for ( size_t day = 0; day < 31; day++ )
1812 {
1813 if ( m_attrs[day] )
1814 {
ca65c044 1815 m_attrs[day]->SetHoliday(false);
4f6aed9c 1816 }
0185cd09
VZ
1817 }
1818}
1819
ab473127
RD
1820
1821//static
1822wxVisualAttributes
1823wxCalendarCtrl::GetClassDefaultAttributes(wxWindowVariant variant)
1824{
1825 // Use the same color scheme as wxListBox
1826 return wxListBox::GetClassDefaultAttributes(variant);
1827}
1828
1e6feb95 1829#endif // wxUSE_CALENDARCTRL
2fa7c206 1830