1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/datectrl.cpp 
   3 // Purpose:     wxDatePickerCtrl implementation 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2005 Vadim Zeitlin <vadim@wxwindows.org> 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #include "wx/wxprec.h" 
  26 #if wxUSE_DATEPICKCTRL 
  31     #include "wx/dcclient.h" 
  32     #include "wx/msw/wrapwin.h" 
  33     #include "wx/msw/wrapcctl.h" 
  34     #include "wx/msw/private.h" 
  37 #include "wx/datectrl.h" 
  38 #include "wx/dynlib.h" 
  40 #define _WX_DEFINE_DATE_EVENTS_ 
  41 #include "wx/dateevt.h" 
  43 // apparently some versions of mingw define these macros erroneously 
  44 #ifndef DateTime_GetSystemtime 
  45     #define DateTime_GetSystemtime DateTime_GetSystemTime 
  48 #ifndef DateTime_SetSystemtime 
  49     #define DateTime_SetSystemtime DateTime_SetSystemTime 
  52 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl
, wxControl
) 
  54 // ============================================================================ 
  56 // ============================================================================ 
  58 // ---------------------------------------------------------------------------- 
  59 // helpers for wxDateTime <-> SYSTEMTIME conversion 
  60 // ---------------------------------------------------------------------------- 
  62 static inline void wxFromSystemTime(wxDateTime 
*dt
, const SYSTEMTIME
& st
) 
  65             wx_static_cast(wxDateTime::Month
, wxDateTime::Jan 
+ st
.wMonth 
- 1), 
  70 static inline void wxToSystemTime(SYSTEMTIME 
*st
, const wxDateTime
& dt
) 
  72     const wxDateTime::Tm 
tm(dt
.GetTm()); 
  74     st
->wYear 
= (WXWORD
)tm
.year
; 
  75     st
->wMonth 
= (WXWORD
)(tm
.mon 
- wxDateTime::Jan 
+ 1); 
  82     st
->wMilliseconds 
= 0; 
  85 // ---------------------------------------------------------------------------- 
  86 // wxDatePickerCtrl creation 
  87 // ---------------------------------------------------------------------------- 
  90 wxDatePickerCtrl::Create(wxWindow 
*parent
, 
  96                          const wxValidator
& validator
, 
  99     // although we already call InitCommonControls() in app.cpp which is 
 100     // supposed to initialize all common controls, in comctl32.dll 4.72 (and 
 101     // presumably earlier versions 4.70 and 4.71, date time picker not being 
 102     // supported in < 4.70 anyhow) it does not do it and we have to initialize 
 104     static bool s_initDone 
= false; // MT-ok: used from GUI thread only 
 108         if ( wxApp::GetComCtl32Version() < 470 ) 
 110             wxLogError(_("This system doesn't support date picker control, please upgrade your version of comctl32.dll")); 
 116 #if wxUSE_DYNLIB_CLASS 
 117         INITCOMMONCONTROLSEX icex
; 
 118         icex
.dwSize 
= sizeof(icex
); 
 119         icex
.dwICC 
= ICC_DATE_CLASSES
; 
 121         wxDynamicLibrary 
dllComCtl32( 
 129         if ( dllComCtl32
.IsLoaded() ) 
 131             typedef BOOL (WINAPI 
*ICCEx_t
)(INITCOMMONCONTROLSEX 
*); 
 132             wxDYNLIB_FUNCTION( ICCEx_t
, InitCommonControlsEx
, dllComCtl32 
); 
 134             if ( pfnInitCommonControlsEx 
) 
 136                 (*pfnInitCommonControlsEx
)(&icex
); 
 145     // use wxDP_SPIN if wxDP_DEFAULT (0) was given as style 
 146     if ( !(style 
& wxDP_DROPDOWN
) ) 
 149     // initialize the base class 
 150     if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 153     // create the native control 
 154     if ( !MSWCreateControl(DATETIMEPICK_CLASS
, wxEmptyString
, pos
, size
) ) 
 157     if ( dt
.IsValid() || (style 
& wxDP_ALLOWNONE
) ) 
 163 WXDWORD 
wxDatePickerCtrl::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 165     WXDWORD styleMSW 
= wxDatePickerCtrlBase::MSWGetStyle(style
, exstyle
); 
 167     // although MSDN doesn't mention it, DTS_UPDOWN doesn't work with 
 169     if ( wxApp::GetComCtl32Version() > 472 && (style 
& wxDP_SPIN
) ) 
 170         styleMSW 
|= DTS_UPDOWN
; 
 171     //else: drop down by default 
 173 #ifdef DTS_SHORTDATECENTURYFORMAT 
 174     if ( style 
& wxDP_SHOWCENTURY 
) 
 175         styleMSW 
|= DTS_SHORTDATECENTURYFORMAT
; 
 177 #endif // DTS_SHORTDATECENTURYFORMAT 
 178         styleMSW 
|= DTS_SHORTDATEFORMAT
; 
 180     if ( style 
& wxDP_ALLOWNONE 
) 
 181         styleMSW 
|= DTS_SHOWNONE
; 
 186 // TODO: handle WM_WININICHANGE 
 188 // ---------------------------------------------------------------------------- 
 189 // wxDatePickerCtrl geometry 
 190 // ---------------------------------------------------------------------------- 
 192 wxSize 
wxDatePickerCtrl::DoGetBestSize() const 
 194     wxClientDC 
dc(wx_const_cast(wxDatePickerCtrl 
*, this)); 
 195     dc
.SetFont(GetFont()); 
 197     // we can't use FormatDate() here as the CRT doesn't always use the same 
 198     // format as the date picker control 
 200     for ( int len 
= 100; ; len 
*= 2 ) 
 204                     LOCALE_USER_DEFAULT
,    // the control should use the same 
 205                     DATE_SHORTDATE
,         // the format used by the control 
 206                     NULL
,                   // use current date (we don't care) 
 207                     NULL
,                   // no custom format 
 208                     wxStringBuffer(s
, len
), // output buffer 
 209                     len                     
// and its length 
 216         const DWORD rc 
= ::GetLastError(); 
 217         if ( rc 
!= ERROR_INSUFFICIENT_BUFFER 
) 
 219             wxLogApiError(_T("GetDateFormat"), rc
); 
 221             // fall back on wxDateTime, what else to do? 
 222             s 
= wxDateTime::Today().FormatDate(); 
 227     // the control adds a lot of extra space around separators 
 228     s
.Replace(_T(","), _T("    ,    ")); 
 231     dc
.GetTextExtent(s
, &x
, &y
); 
 233     wxSize 
best(x 
+ 40 /* margin + arrows */, EDIT_HEIGHT_FROM_CHAR_HEIGHT(y
)); 
 238 // ---------------------------------------------------------------------------- 
 239 // wxDatePickerCtrl operations 
 240 // ---------------------------------------------------------------------------- 
 242 void wxDatePickerCtrl::SetValue(const wxDateTime
& dt
) 
 244     wxCHECK_RET( dt
.IsValid() || HasFlag(wxDP_ALLOWNONE
), 
 245                     _T("this control requires a valid date") ); 
 249         wxToSystemTime(&st
, dt
); 
 250     if ( !DateTime_SetSystemtime(GetHwnd(), 
 251                                  dt
.IsValid() ? GDT_VALID 
: GDT_NONE
, 
 254         wxLogDebug(_T("DateTime_SetSystemtime() failed")); 
 258 wxDateTime 
wxDatePickerCtrl::GetValue() const 
 262     if ( DateTime_GetSystemtime(GetHwnd(), &st
) == GDT_VALID 
) 
 264         wxFromSystemTime(&dt
, st
); 
 270 void wxDatePickerCtrl::SetRange(const wxDateTime
& dt1
, const wxDateTime
& dt2
) 
 277         wxToSystemTime(&st
[0], dt1
); 
 283         wxToSystemTime(&st
[1], dt2
); 
 287     if ( !DateTime_SetRange(GetHwnd(), flags
, st
) ) 
 289         wxLogDebug(_T("DateTime_SetRange() failed")); 
 293 bool wxDatePickerCtrl::GetRange(wxDateTime 
*dt1
, wxDateTime 
*dt2
) const 
 297     DWORD flags 
= DateTime_GetRange(GetHwnd(), st
); 
 300         if ( flags 
& GDTR_MIN 
) 
 301             wxFromSystemTime(dt1
, st
[0]); 
 303             *dt1 
= wxDefaultDateTime
; 
 308         if ( flags 
& GDTR_MAX 
) 
 309             wxFromSystemTime(dt2
, st
[1]); 
 311             *dt2 
= wxDefaultDateTime
; 
 317 // ---------------------------------------------------------------------------- 
 318 // wxDatePickerCtrl events 
 319 // ---------------------------------------------------------------------------- 
 322 wxDatePickerCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM 
*result
) 
 324     NMHDR
* hdr 
= (NMHDR 
*)lParam
; 
 327         case DTN_DATETIMECHANGE
: 
 329             NMDATETIMECHANGE 
*dtch 
= (NMDATETIMECHANGE 
*)hdr
; 
 331             if ( dtch
->dwFlags 
== GDT_VALID 
) 
 332                 wxFromSystemTime(&dt
, dtch
->st
); 
 334             wxDateEvent 
event(this, dt
, wxEVT_DATE_CHANGED
); 
 335             if ( GetEventHandler()->ProcessEvent(event
) ) 
 343     return wxDatePickerCtrlBase::MSWOnNotify(idCtrl
, lParam
, result
); 
 346 #endif // wxUSE_DATEPICKCTRL