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