1 /////////////////////////////////////////////////////////////////////////////
2 // Name: generic/datectlg.cpp
3 // Purpose: generic wxDatePickerCtrlGeneric implementation
4 // Author: Andreas Pflug
8 // Copyright: (c) 2005 Andreas Pflug <pgadmin@pse-consulting.de>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
26 #if wxUSE_DATEPICKCTRL
28 #include "wx/datectrl.h"
30 // use this version if we're explicitly requested to do it or if it's the only
32 #if wxUSE_DATEPICKCTRL_GENERIC || !defined(wxHAS_NATIVE_DATEPICKCTRL)
35 #include "wx/bmpbuttn.h"
36 #include "wx/dialog.h"
37 #include "wx/dcmemory.h"
39 #include "wx/textctrl.h"
40 #include "wx/valtext.h"
43 #ifdef wxHAS_NATIVE_DATEPICKCTRL
44 // this header is not included from wx/datectrl.h if we have a native
45 // version, but we do need it here
46 #include "wx/generic/datectrl.h"
49 // we need to define _WX_DEFINE_DATE_EVENTS_ before including wx/dateevt.h to
50 // define the event types we use if we're the only date picker control version
51 // being compiled -- otherwise it's defined in the native version implementation
52 #ifndef wxHAS_NATIVE_DATEPICKCTRL
53 #define _WX_DEFINE_DATE_EVENTS_
56 #include "wx/dateevt.h"
58 #include "wx/calctrl.h"
59 #include "wx/renderer.h"
61 // ----------------------------------------------------------------------------
63 // ----------------------------------------------------------------------------
73 #ifndef DEFAULT_ITEM_WIDTH
74 #define DEFAULT_ITEM_WIDTH 100
77 // ----------------------------------------------------------------------------
79 // ----------------------------------------------------------------------------
83 #include "wx/popupwin.h"
85 class wxDatePopupInternal
: public wxPopupTransientWindow
88 wxDatePopupInternal(wxWindow
*parent
) : wxPopupTransientWindow(parent
) { }
90 void ShowAt(int x
, int y
)
92 Position(wxPoint(x
, y
), wxSize(0, 0));
102 #else // !wxUSE_POPUPWIN
104 class wxDatePopupInternal
: public wxDialog
107 wxDatePopupInternal(wxWindow
*parent
)
117 void ShowAt(int x
, int y
)
129 #endif // wxUSE_POPUPWIN/!wxUSE_POPUPWIN
131 // ============================================================================
132 // wxDatePickerCtrlGeneric implementation
133 // ============================================================================
135 BEGIN_EVENT_TABLE(wxDatePickerCtrlGeneric
, wxDatePickerCtrlBase
)
136 EVT_BUTTON(CTRLID_BTN
, wxDatePickerCtrlGeneric::OnClick
)
137 EVT_TEXT(CTRLID_TXT
, wxDatePickerCtrlGeneric::OnText
)
138 EVT_CHILD_FOCUS(wxDatePickerCtrlGeneric::OnChildSetFocus
)
141 #ifndef wxHAS_NATIVE_DATEPICKCTRL
142 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl
, wxDatePickerCtrlBase
)
145 // ----------------------------------------------------------------------------
147 // ----------------------------------------------------------------------------
149 bool wxDatePickerCtrlGeneric::Create(wxWindow
*parent
,
151 const wxDateTime
& date
,
155 const wxValidator
& validator
,
156 const wxString
& name
)
158 wxASSERT_MSG( !(style
& wxDP_SPIN
),
159 _T("wxDP_SPIN style not supported, use wxDP_DEFAULT") );
161 if ( !wxControl::Create(parent
, id
, pos
, size
,
162 style
| wxCLIP_CHILDREN
| wxWANTS_CHARS
,
171 m_txt
= new wxTextCtrl(this, CTRLID_TXT
);
172 m_txt
->Connect(wxEVT_KEY_DOWN
,
173 wxKeyEventHandler(wxDatePickerCtrlGeneric::OnEditKey
),
175 m_txt
->Connect(wxEVT_KILL_FOCUS
,
176 wxFocusEventHandler(wxDatePickerCtrlGeneric::OnKillFocus
),
179 const int height
= m_txt
->GetBestSize().y
- 4; // FIXME: fudge
180 wxBitmap
bmp(height
, height
);
183 dc
.SelectObject(bmp
);
184 wxRendererNative::Get().DrawComboBoxDropButton
188 wxRect(0, 0, height
, height
)
192 wxBitmapButton
*btn
= new wxBitmapButton(this, CTRLID_BTN
, bmp
);
193 btn
->SetMargins(0, 0);
196 m_popup
= new wxDatePopupInternal(this);
197 m_popup
->SetFont(GetFont());
199 wxPanel
*panel
=new wxPanel(m_popup
, CTRLID_PAN
,
200 wxPoint(0, 0), wxDefaultSize
,
202 m_cal
= new wxCalendarCtrl(panel
, CTRLID_CAL
, wxDefaultDateTime
,
203 wxPoint(0, 0), wxDefaultSize
,
204 wxCAL_SHOW_HOLIDAYS
| wxSUNKEN_BORDER
);
205 m_cal
->Connect(wxEVT_CALENDAR_SEL_CHANGED
,
206 wxCalendarEventHandler(wxDatePickerCtrlGeneric::OnSelChange
),
208 m_cal
->Connect(wxEVT_KEY_DOWN
,
209 wxKeyEventHandler(wxDatePickerCtrlGeneric::OnCalKey
),
211 m_cal
->Connect(wxEVT_CALENDAR_DOUBLECLICKED
,
212 wxCalendarEventHandler(wxDatePickerCtrlGeneric::OnSelChange
),
214 m_cal
->Connect(wxEVT_CALENDAR_DAY_CHANGED
,
215 wxCalendarEventHandler(wxDatePickerCtrlGeneric::OnSelChange
),
217 m_cal
->Connect(wxEVT_CALENDAR_MONTH_CHANGED
,
218 wxCalendarEventHandler(wxDatePickerCtrlGeneric::OnSelChange
),
220 m_cal
->Connect(wxEVT_CALENDAR_YEAR_CHANGED
,
221 wxCalendarEventHandler(wxDatePickerCtrlGeneric::OnSelChange
),
224 wxWindow
*yearControl
= m_cal
->GetYearControl();
226 Connect(wxEVT_SET_FOCUS
,
227 wxFocusEventHandler(wxDatePickerCtrlGeneric::OnSetFocus
));
229 wxClientDC
dc(yearControl
);
231 wxCoord width
, dummy
;
232 dc
.GetTextExtent(wxT("2000"), &width
, &dummy
);
233 width
+= ConvertDialogToPixels(wxSize(20, 0)).x
;
235 wxSize calSize
= m_cal
->GetBestSize();
236 wxSize yearSize
= yearControl
->GetSize();
239 wxPoint yearPosition
= yearControl
->GetPosition();
241 SetFormat(wxT("%x"));
246 #define RIGHTBUTTONBORDER 2
247 #define TOPBUTTONBORDER 1
250 #define RIGHTBUTTONBORDER 0
251 #define TOPBUTTONBORDER 0
254 width
= yearPosition
.x
+ yearSize
.x
+2+CALBORDER
/2;
255 if (width
< calSize
.x
-4)
258 int calPos
= (width
-calSize
.x
)/2;
264 m_cal
->SetSize(calPos
, 0, calSize
.x
, calSize
.y
);
265 yearControl
->SetSize(width
-yearSize
.x
-CALBORDER
/2, yearPosition
.y
,
266 yearSize
.x
, yearSize
.y
);
267 m_cal
->GetMonthControl()->Move(0, 0);
271 panel
->SetClientSize(width
+CALBORDER
/2, calSize
.y
-2+CALBORDER
);
272 m_popup
->SetClientSize(panel
->GetSize());
284 void wxDatePickerCtrlGeneric::Init()
292 m_ignoreDrop
= false;
296 bool wxDatePickerCtrlGeneric::Destroy()
312 return wxControl::Destroy();
315 // ----------------------------------------------------------------------------
316 // overridden base class methods
317 // ----------------------------------------------------------------------------
319 void wxDatePickerCtrlGeneric::DoMoveWindow(int x
, int y
, int w
, int h
)
321 wxControl::DoMoveWindow(x
, y
, w
, h
);
322 wxSize bs
=m_btn
->GetBestSize();
323 int eh
=m_txt
->GetBestSize().y
;
325 m_txt
->SetSize(0, 0, w
-bs
.x
-1, h
> eh
? eh
: h
);
326 m_btn
->SetSize(w
- bs
.x
-RIGHTBUTTONBORDER
, TOPBUTTONBORDER
, bs
.x
, h
> bs
.y
? bs
.y
: h
);
332 wxSize
wxDatePickerCtrlGeneric::DoGetBestSize() const
334 int bh
=m_btn
->GetBestSize().y
;
335 int eh
=m_txt
->GetBestSize().y
;
336 return wxSize(DEFAULT_ITEM_WIDTH
, bh
> eh
? bh
: eh
);
340 bool wxDatePickerCtrlGeneric::Show(bool show
)
342 if ( !wxControl::Show(show
) )
360 bool wxDatePickerCtrlGeneric::Enable(bool enable
)
362 if ( !wxControl::Enable(enable
) )
374 m_btn
->Enable(enable
);
379 // ----------------------------------------------------------------------------
380 // wxDatePickerCtrlGeneric API
381 // ----------------------------------------------------------------------------
384 wxDatePickerCtrlGeneric::SetDateRange(const wxDateTime
& lowerdate
,
385 const wxDateTime
& upperdate
)
387 return m_cal
->SetDateRange(lowerdate
, upperdate
);
390 bool wxDatePickerCtrlGeneric::SetFormat(const wxChar
*fmt
)
393 dt
.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d"));
394 wxString str
=dt
.Format(fmt
);
395 wxChar
*p
=(wxChar
*)str
.c_str();
397 m_format
=wxEmptyString
;
402 if (n
== dt
.GetDay())
404 m_format
.Append(wxT("%d"));
407 else if (n
== (int)dt
.GetMonth()+1)
409 m_format
.Append(wxT("%m"));
412 else if (n
== dt
.GetYear())
414 m_format
.Append(wxT("%Y"));
417 else if (n
== (dt
.GetYear() % 100))
419 if (GetWindowStyle() & wxDP_SHOWCENTURY
)
420 m_format
.Append(wxT("%Y"));
422 m_format
.Append(wxT("%y"));
426 m_format
.Append(*p
++);
431 wxArrayString allowedChars
;
432 for ( wxChar c
= _T('0'); c
<= _T('9'); c
++ )
433 allowedChars
.Add(wxString(c
, 1));
435 const wxChar
*p
= m_format
.c_str();
441 allowedChars
.Add(wxString(*p
++, 1));
444 wxTextValidator
tv(wxFILTER_INCLUDE_CHAR_LIST
);
445 tv
.SetIncludes(allowedChars
);
447 m_txt
->SetValidator(tv
);
449 if (m_currentDate
.IsValid())
450 m_txt
->SetValue(m_currentDate
.Format(m_format
));
457 wxDateTime
wxDatePickerCtrlGeneric::GetValue() const
459 return m_currentDate
;
463 void wxDatePickerCtrlGeneric::SetValue(const wxDateTime
& date
)
468 m_txt
->SetValue(date
.Format(m_format
));
471 wxASSERT_MSG( HasFlag(wxDP_ALLOWNONE
),
472 _T("this control must have a valid date") );
474 m_txt
->SetValue(wxEmptyString
);
477 m_currentDate
= date
;
482 bool wxDatePickerCtrlGeneric::GetRange(wxDateTime
*dt1
, wxDateTime
*dt2
) const
485 *dt1
= m_cal
->GetLowerDateLimit();
487 *dt2
= m_cal
->GetUpperDateLimit();
493 wxDatePickerCtrlGeneric::SetRange(const wxDateTime
&dt1
, const wxDateTime
&dt2
)
495 m_cal
->SetDateRange(dt1
, dt2
);
498 // ----------------------------------------------------------------------------
500 // ----------------------------------------------------------------------------
502 void wxDatePickerCtrlGeneric::DropDown(bool down
)
509 if (!m_txt
->GetValue().empty())
510 dt
.ParseFormat(m_txt
->GetValue(), m_format
);
515 m_cal
->SetDate(wxDateTime::Today());
517 wxPoint pos
=GetParent()->ClientToScreen(GetPosition());
518 m_popup
->ShowAt(pos
.x
, pos
.y
+ GetSize().y
);
532 void wxDatePickerCtrlGeneric::OnChildSetFocus(wxChildFocusEvent
&ev
)
535 m_ignoreDrop
= false;
537 wxWindow
*w
=(wxWindow
*)ev
.GetEventObject();
548 if (ev
.GetEventObject() == m_btn
)
554 void wxDatePickerCtrlGeneric::OnClick(wxCommandEvent
& WXUNUSED(event
))
558 m_ignoreDrop
= false;
569 void wxDatePickerCtrlGeneric::OnSetFocus(wxFocusEvent
& WXUNUSED(ev
))
574 m_txt
->SetSelection(-1, -1); // select everything
579 void wxDatePickerCtrlGeneric::OnKillFocus(wxFocusEvent
&ev
)
584 dt
.ParseFormat(m_txt
->GetValue(), m_format
);
587 if ( !HasFlag(wxDP_ALLOWNONE
) )
592 m_txt
->SetValue(dt
.Format(m_format
));
594 m_txt
->SetValue(wxEmptyString
);
596 // notify that we had to change the date after validation
597 if ( (dt
.IsValid() && m_currentDate
!= dt
) ||
598 (!dt
.IsValid() && m_currentDate
.IsValid()) )
601 wxDateEvent
event(this, dt
, wxEVT_DATE_CHANGED
);
602 GetEventHandler()->ProcessEvent(event
);
607 void wxDatePickerCtrlGeneric::OnSelChange(wxCalendarEvent
&ev
)
611 m_currentDate
= m_cal
->GetDate();
612 m_txt
->SetValue(m_currentDate
.Format(m_format
));
613 if (ev
.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED
)
619 ev
.SetEventObject(this);
621 GetParent()->ProcessEvent(ev
);
623 wxDateEvent
dev(this, ev
.GetDate(), wxEVT_DATE_CHANGED
);
624 GetParent()->ProcessEvent(dev
);
628 void wxDatePickerCtrlGeneric::OnText(wxCommandEvent
&ev
)
630 ev
.SetEventObject(this);
632 GetParent()->ProcessEvent(ev
);
634 // We'll create an additional event if the date is valid.
635 // If the date isn't valid, the user's probably in the middle of typing
636 wxString txt
= m_txt
->GetValue();
640 dt
.ParseFormat(txt
, m_format
);
645 wxCalendarEvent
cev(m_cal
, wxEVT_CALENDAR_SEL_CHANGED
);
646 cev
.SetEventObject(this);
650 GetParent()->ProcessEvent(cev
);
652 wxDateEvent
dev(this, dt
, wxEVT_DATE_CHANGED
);
653 GetParent()->ProcessEvent(dev
);
657 void wxDatePickerCtrlGeneric::OnEditKey(wxKeyEvent
& ev
)
659 if (ev
.GetKeyCode() == WXK_DOWN
&& !ev
.HasModifiers())
666 void wxDatePickerCtrlGeneric::OnCalKey(wxKeyEvent
& ev
)
668 if (ev
.GetKeyCode() == WXK_ESCAPE
&& !ev
.HasModifiers())
674 #endif // wxUSE_DATEPICKCTRL_GENERIC
676 #endif // wxUSE_DATEPICKCTRL