]> git.saurik.com Git - wxWidgets.git/blame - src/msw/datectrl.cpp
include wx/crt.h needed for wxFprintf() (closes #9509)
[wxWidgets.git] / src / msw / datectrl.cpp
CommitLineData
feb72429 1/////////////////////////////////////////////////////////////////////////////
02e05e7e 2// Name: src/msw/datectrl.cpp
feb72429
VZ
3// Purpose: wxDatePickerCtrl implementation
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 2005-01-09
7// RCS-ID: $Id$
8// Copyright: (c) 2005 Vadim Zeitlin <vadim@wxwindows.org>
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
02e05e7e
WS
26#if wxUSE_DATEPICKCTRL
27
feb72429 28#ifndef WX_PRECOMP
57bd4c60
WS
29 #include "wx/msw/wrapwin.h"
30 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
02e05e7e
WS
31 #include "wx/app.h"
32 #include "wx/intl.h"
33 #include "wx/dcclient.h"
02e05e7e 34 #include "wx/msw/private.h"
feb72429
VZ
35#endif
36
37#include "wx/datectrl.h"
51317496
VZ
38
39#include "wx/msw/private/datecontrols.h"
feb72429 40
feb72429
VZ
41#include "wx/dateevt.h"
42
3200f37d
VZ
43// apparently some versions of mingw define these macros erroneously
44#ifndef DateTime_GetSystemtime
45 #define DateTime_GetSystemtime DateTime_GetSystemTime
46#endif
47
48#ifndef DateTime_SetSystemtime
49 #define DateTime_SetSystemtime DateTime_SetSystemTime
65ab1002
JS
50#endif
51
a69e2a0a
VZ
52IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl)
53
feb72429
VZ
54// ============================================================================
55// implementation
56// ============================================================================
57
feb72429
VZ
58// ----------------------------------------------------------------------------
59// wxDatePickerCtrl creation
60// ----------------------------------------------------------------------------
61
62bool
63wxDatePickerCtrl::Create(wxWindow *parent,
64 wxWindowID id,
65 const wxDateTime& dt,
66 const wxPoint& pos,
67 const wxSize& size,
68 long style,
69 const wxValidator& validator,
70 const wxString& name)
71{
51317496
VZ
72 if ( !wxMSWDateControls::CheckInitialization() )
73 return false;
0aa7cb54 74
5385747e
VZ
75 // use wxDP_SPIN if wxDP_DEFAULT (0) was given as style
76 if ( !(style & wxDP_DROPDOWN) )
77 style |= wxDP_SPIN;
78
feb72429
VZ
79 // initialize the base class
80 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
81 return false;
82
83 // create the native control
f31a4098 84 if ( !MSWCreateControl(DATETIMEPICK_CLASS, wxEmptyString, pos, size) )
feb72429
VZ
85 return false;
86
bab3f3ea 87 if ( dt.IsValid() || (style & wxDP_ALLOWNONE) )
feb72429 88 SetValue(dt);
4d536421
RD
89 else
90 SetValue(wxDateTime::Today());
feb72429
VZ
91
92 return true;
93}
94
95WXDWORD wxDatePickerCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
96{
97 WXDWORD styleMSW = wxDatePickerCtrlBase::MSWGetStyle(style, exstyle);
98
0aa7cb54
VZ
99 // although MSDN doesn't mention it, DTS_UPDOWN doesn't work with
100 // comctl32.dll 4.72
2a1f999f 101 if ( wxApp::GetComCtl32Version() > 472 && (style & wxDP_SPIN) )
29c86948
VZ
102 styleMSW |= DTS_UPDOWN;
103 //else: drop down by default
104
2cfbeac8
VZ
105#ifdef DTS_SHORTDATECENTURYFORMAT
106 if ( style & wxDP_SHOWCENTURY )
107 styleMSW |= DTS_SHORTDATECENTURYFORMAT;
108 else
109#endif // DTS_SHORTDATECENTURYFORMAT
110 styleMSW |= DTS_SHORTDATEFORMAT;
feb72429 111
3200f37d
VZ
112 if ( style & wxDP_ALLOWNONE )
113 styleMSW |= DTS_SHOWNONE;
114
feb72429
VZ
115 return styleMSW;
116}
117
118// TODO: handle WM_WININICHANGE
119
120// ----------------------------------------------------------------------------
121// wxDatePickerCtrl geometry
122// ----------------------------------------------------------------------------
123
124wxSize wxDatePickerCtrl::DoGetBestSize() const
125{
c01359d9
VZ
126 wxClientDC dc(wx_const_cast(wxDatePickerCtrl *, this));
127 dc.SetFont(GetFont());
feb72429 128
c01359d9
VZ
129 // we can't use FormatDate() here as the CRT doesn't always use the same
130 // format as the date picker control
131 wxString s;
132 for ( int len = 100; ; len *= 2 )
133 {
134 if ( ::GetDateFormat
135 (
136 LOCALE_USER_DEFAULT, // the control should use the same
137 DATE_SHORTDATE, // the format used by the control
138 NULL, // use current date (we don't care)
139 NULL, // no custom format
140 wxStringBuffer(s, len), // output buffer
141 len // and its length
142 ) )
143 {
144 // success
145 break;
146 }
147
148 const DWORD rc = ::GetLastError();
149 if ( rc != ERROR_INSUFFICIENT_BUFFER )
150 {
151 wxLogApiError(_T("GetDateFormat"), rc);
152
153 // fall back on wxDateTime, what else to do?
154 s = wxDateTime::Today().FormatDate();
155 break;
156 }
157 }
158
159 // the control adds a lot of extra space around separators
160 s.Replace(_T(","), _T(" , "));
161
162 int x, y;
163 dc.GetTextExtent(s, &x, &y);
164
165 wxSize best(x + 40 /* margin + arrows */, EDIT_HEIGHT_FROM_CHAR_HEIGHT(y));
31582e4e
RD
166 CacheBestSize(best);
167 return best;
feb72429
VZ
168}
169
170// ----------------------------------------------------------------------------
171// wxDatePickerCtrl operations
172// ----------------------------------------------------------------------------
173
174void wxDatePickerCtrl::SetValue(const wxDateTime& dt)
175{
3200f37d
VZ
176 wxCHECK_RET( dt.IsValid() || HasFlag(wxDP_ALLOWNONE),
177 _T("this control requires a valid date") );
feb72429
VZ
178
179 SYSTEMTIME st;
3200f37d 180 if ( dt.IsValid() )
154014d6 181 dt.GetAsMSWSysTime(&st);
3200f37d
VZ
182 if ( !DateTime_SetSystemtime(GetHwnd(),
183 dt.IsValid() ? GDT_VALID : GDT_NONE,
184 &st) )
feb72429
VZ
185 {
186 wxLogDebug(_T("DateTime_SetSystemtime() failed"));
187 }
e4164aa9 188
5541976c
VZ
189 // we need to keep only the date part, times don't make sense for this
190 // control (in particular, comparisons with other dates would fail)
28039907 191 m_date = dt;
0bdd8074
VZ
192 if ( m_date.IsValid() )
193 m_date.ResetTime();
feb72429
VZ
194}
195
196wxDateTime wxDatePickerCtrl::GetValue() const
197{
e4164aa9 198#ifdef __WXDEBUG__
feb72429
VZ
199 wxDateTime dt;
200 SYSTEMTIME st;
201 if ( DateTime_GetSystemtime(GetHwnd(), &st) == GDT_VALID )
202 {
154014d6 203 dt.SetFromMSWSysTime(st);
feb72429
VZ
204 }
205
e4164aa9
VZ
206 wxASSERT_MSG( m_date.IsValid() == dt.IsValid() &&
207 (!dt.IsValid() || dt == m_date),
208 _T("bug in wxDatePickerCtrl: m_date not in sync") );
209#endif // __WXDEBUG__
210
211 return m_date;
feb72429
VZ
212}
213
214void wxDatePickerCtrl::SetRange(const wxDateTime& dt1, const wxDateTime& dt2)
215{
216 SYSTEMTIME st[2];
217
218 DWORD flags = 0;
219 if ( dt1.IsValid() )
220 {
154014d6 221 dt1.GetAsMSWSysTime(st + 0);
feb72429
VZ
222 flags |= GDTR_MIN;
223 }
224
225 if ( dt2.IsValid() )
226 {
154014d6 227 dt2.GetAsMSWSysTime(st + 1);
feb72429
VZ
228 flags |= GDTR_MAX;
229 }
230
231 if ( !DateTime_SetRange(GetHwnd(), flags, st) )
232 {
233 wxLogDebug(_T("DateTime_SetRange() failed"));
234 }
235}
236
237bool wxDatePickerCtrl::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
238{
239 SYSTEMTIME st[2];
240
241 DWORD flags = DateTime_GetRange(GetHwnd(), st);
242 if ( dt1 )
243 {
244 if ( flags & GDTR_MIN )
154014d6 245 dt1->SetFromMSWSysTime(st[0]);
feb72429
VZ
246 else
247 *dt1 = wxDefaultDateTime;
248 }
249
250 if ( dt2 )
251 {
252 if ( flags & GDTR_MAX )
154014d6 253 dt2->SetFromMSWSysTime(st[1]);
feb72429
VZ
254 else
255 *dt2 = wxDefaultDateTime;
256 }
257
258 return flags != 0;
259}
260
261// ----------------------------------------------------------------------------
262// wxDatePickerCtrl events
263// ----------------------------------------------------------------------------
264
265bool
266wxDatePickerCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
267{
268 NMHDR* hdr = (NMHDR *)lParam;
269 switch ( hdr->code )
270 {
271 case DTN_DATETIMECHANGE:
b4446c24 272 {
feb72429
VZ
273 NMDATETIMECHANGE *dtch = (NMDATETIMECHANGE *)hdr;
274 wxDateTime dt;
275 if ( dtch->dwFlags == GDT_VALID )
154014d6 276 dt.SetFromMSWSysTime(dtch->st);
feb72429 277
e4164aa9
VZ
278 // filter out duplicate DTN_DATETIMECHANGE events which the native
279 // control sends us when using wxDP_DROPDOWN style
0c8433d0
VZ
280 if ( (m_date.IsValid() != dt.IsValid()) ||
281 (m_date.IsValid() && dt != m_date) )
feb72429 282 {
e4164aa9
VZ
283 m_date = dt;
284 wxDateEvent event(this, dt, wxEVT_DATE_CHANGED);
937013e0 285 if ( HandleWindowEvent(event) )
e4164aa9
VZ
286 {
287 *result = 0;
288 return true;
289 }
feb72429 290 }
0c8433d0 291 //else: both the old and new values are invalid, nothing changed
b4446c24 292 }
feb72429
VZ
293 }
294
295 return wxDatePickerCtrlBase::MSWOnNotify(idCtrl, lParam, result);
296}
297
9b877d18 298#endif // wxUSE_DATEPICKCTRL