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(wxID_ANY
, wxID_ANY
, wxEVT_KEY_DOWN
, 
 173                    (wxObjectEventFunction
)&wxDatePickerCtrlGeneric::OnEditKey
, 
 175     m_txt
->Connect(wxID_ANY
, wxID_ANY
, wxEVT_KILL_FOCUS
, 
 176                    (wxObjectEventFunction
)&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(CTRLID_CAL
, CTRLID_CAL
, wxEVT_CALENDAR_SEL_CHANGED
, 
 206                    (wxObjectEventFunction
)&wxDatePickerCtrlGeneric::OnSelChange
, 
 208     m_cal
->Connect(wxID_ANY
, wxID_ANY
, wxEVT_KEY_DOWN
, 
 209                    (wxObjectEventFunction
)&wxDatePickerCtrlGeneric::OnCalKey
, 
 211     m_cal
->Connect(CTRLID_CAL
, CTRLID_CAL
, wxEVT_CALENDAR_DOUBLECLICKED
, 
 212                    (wxObjectEventFunction
)&wxDatePickerCtrlGeneric::OnSelChange
, 
 214     m_cal
->Connect(CTRLID_CAL
, CTRLID_CAL
, wxEVT_CALENDAR_DAY_CHANGED
, 
 215                    (wxObjectEventFunction
)&wxDatePickerCtrlGeneric::OnSelChange
, 
 217     m_cal
->Connect(CTRLID_CAL
, CTRLID_CAL
, wxEVT_CALENDAR_MONTH_CHANGED
, 
 218                    (wxObjectEventFunction
)&wxDatePickerCtrlGeneric::OnSelChange
, 
 220     m_cal
->Connect(CTRLID_CAL
, CTRLID_CAL
, wxEVT_CALENDAR_YEAR_CHANGED
, 
 221                    (wxObjectEventFunction
)&wxDatePickerCtrlGeneric::OnSelChange
, 
 224     wxWindow 
*yearControl 
= m_cal
->GetYearControl(); 
 226     Connect(wxID_ANY
, wxID_ANY
, wxEVT_SET_FOCUS
, 
 227             (wxObjectEventFunction
)&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