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