corrected wxRTTI macros
[wxWidgets.git] / src / msw / datectrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/datectrl.cpp
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
26 #ifndef WX_PRECOMP
27 #endif
28
29 #if wxUSE_DATEPICKCTRL
30
31 #include "wx/datectrl.h"
32 #include "wx/app.h"
33 #include "wx/intl.h"
34 #include "wx/dynlib.h"
35
36 #define _WX_DEFINE_DATE_EVENTS_
37 #include "wx/dateevt.h"
38
39 #include "wx/msw/wrapwin.h"
40 #include "wx/msw/wrapcctl.h"
41 #include "wx/msw/private.h"
42
43 #if defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 2, 4 )
44 typedef struct tagNMDATETIMECHANGE
45 {
46 NMHDR nmhdr;
47 DWORD dwFlags;
48 SYSTEMTIME st;
49 } NMDATETIMECHANGE;
50 #endif // old gcc headers
51
52 // apparently some versions of mingw define these macros erroneously
53 #ifndef DateTime_GetSystemtime
54 #define DateTime_GetSystemtime DateTime_GetSystemTime
55 #endif
56
57 #ifndef DateTime_SetSystemtime
58 #define DateTime_SetSystemtime DateTime_SetSystemTime
59 #endif
60
61 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxControl)
62
63 // ============================================================================
64 // implementation
65 // ============================================================================
66
67 // ----------------------------------------------------------------------------
68 // helpers for wxDateTime <-> SYSTEMTIME conversion
69 // ----------------------------------------------------------------------------
70
71 static inline void wxFromSystemTime(wxDateTime *dt, const SYSTEMTIME& st)
72 {
73 dt->Set(st.wDay,
74 wx_static_cast(wxDateTime::Month, wxDateTime::Jan + st.wMonth - 1),
75 st.wYear,
76 0, 0, 0);
77 }
78
79 static inline void wxToSystemTime(SYSTEMTIME *st, const wxDateTime& dt)
80 {
81 const wxDateTime::Tm tm(dt.GetTm());
82
83 st->wYear = (WXWORD)tm.year;
84 st->wMonth = (WXWORD)(tm.mon - wxDateTime::Jan + 1);
85 st->wDay = tm.mday;
86
87 st->wDayOfWeek =
88 st->wHour =
89 st->wMinute =
90 st->wSecond =
91 st->wMilliseconds = 0;
92 }
93
94 // ----------------------------------------------------------------------------
95 // wxDatePickerCtrl creation
96 // ----------------------------------------------------------------------------
97
98 bool
99 wxDatePickerCtrl::Create(wxWindow *parent,
100 wxWindowID id,
101 const wxDateTime& dt,
102 const wxPoint& pos,
103 const wxSize& size,
104 long style,
105 const wxValidator& validator,
106 const wxString& name)
107 {
108 // although we already call InitCommonControls() in app.cpp which is
109 // supposed to initialize all common controls, in comctl32.dll 4.72 (and
110 // presumably earlier versions 4.70 and 4.71, date time picker not being
111 // supported in < 4.70 anyhow) it does not do it and we have to initialize
112 // it explicitely
113 static bool s_initDone = false; // MT-ok: used from GUI thread only
114 if ( !s_initDone )
115 {
116 if ( wxTheApp->GetComCtl32Version() < 470 )
117 {
118 wxLogError(_("This system doesn't support date picker control, please upgrade your version of comctl32.dll"));
119
120 return false;
121 }
122
123 INITCOMMONCONTROLSEX icex;
124 icex.dwSize = sizeof(icex);
125 icex.dwICC = ICC_DATE_CLASSES;
126
127 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
128
129 typedef BOOL (WINAPI *ICCEx_t)(INITCOMMONCONTROLSEX *);
130 wxDYNLIB_FUNCTION( ICCEx_t, InitCommonControlsEx, dllComCtl32 );
131
132 if ( pfnInitCommonControlsEx )
133 {
134 (*pfnInitCommonControlsEx)(&icex);
135 }
136
137 s_initDone = true;
138 }
139
140
141 // use wxDP_SPIN if wxDP_DEFAULT (0) was given as style
142 if ( !(style & wxDP_DROPDOWN) )
143 style |= wxDP_SPIN;
144
145 // initialize the base class
146 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
147 return false;
148
149 // create the native control
150 if ( !MSWCreateControl(DATETIMEPICK_CLASS, wxEmptyString, pos, size) )
151 return false;
152
153 if ( dt.IsValid() )
154 SetValue(dt);
155
156 return true;
157 }
158
159 WXDWORD wxDatePickerCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
160 {
161 WXDWORD styleMSW = wxDatePickerCtrlBase::MSWGetStyle(style, exstyle);
162
163 // although MSDN doesn't mention it, DTS_UPDOWN doesn't work with
164 // comctl32.dll 4.72
165 if ( wxTheApp->GetComCtl32Version() > 472 && (style & wxDP_SPIN) )
166 styleMSW |= DTS_UPDOWN;
167 //else: drop down by default
168
169 #ifdef DTS_SHORTDATECENTURYFORMAT
170 if ( style & wxDP_SHOWCENTURY )
171 styleMSW |= DTS_SHORTDATECENTURYFORMAT;
172 else
173 #endif // DTS_SHORTDATECENTURYFORMAT
174 styleMSW |= DTS_SHORTDATEFORMAT;
175
176 if ( style & wxDP_ALLOWNONE )
177 styleMSW |= DTS_SHOWNONE;
178
179 return styleMSW;
180 }
181
182 // TODO: handle WM_WININICHANGE
183
184 // ----------------------------------------------------------------------------
185 // wxDatePickerCtrl geometry
186 // ----------------------------------------------------------------------------
187
188 wxSize wxDatePickerCtrl::DoGetBestSize() const
189 {
190 const int y = GetCharHeight();
191
192 return wxSize(DEFAULT_ITEM_WIDTH, EDIT_HEIGHT_FROM_CHAR_HEIGHT(y));
193 }
194
195 // ----------------------------------------------------------------------------
196 // wxDatePickerCtrl operations
197 // ----------------------------------------------------------------------------
198
199 void wxDatePickerCtrl::SetValue(const wxDateTime& dt)
200 {
201 wxCHECK_RET( dt.IsValid() || HasFlag(wxDP_ALLOWNONE),
202 _T("this control requires a valid date") );
203
204 SYSTEMTIME st;
205 if ( dt.IsValid() )
206 wxToSystemTime(&st, dt);
207 if ( !DateTime_SetSystemtime(GetHwnd(),
208 dt.IsValid() ? GDT_VALID : GDT_NONE,
209 &st) )
210 {
211 wxLogDebug(_T("DateTime_SetSystemtime() failed"));
212 }
213 }
214
215 wxDateTime wxDatePickerCtrl::GetValue() const
216 {
217 wxDateTime dt;
218 SYSTEMTIME st;
219 if ( DateTime_GetSystemtime(GetHwnd(), &st) == GDT_VALID )
220 {
221 wxFromSystemTime(&dt, st);
222 }
223
224 return dt;
225 }
226
227 void wxDatePickerCtrl::SetRange(const wxDateTime& dt1, const wxDateTime& dt2)
228 {
229 SYSTEMTIME st[2];
230
231 DWORD flags = 0;
232 if ( dt1.IsValid() )
233 {
234 wxToSystemTime(&st[0], dt1);
235 flags |= GDTR_MIN;
236 }
237
238 if ( dt2.IsValid() )
239 {
240 wxToSystemTime(&st[1], dt2);
241 flags |= GDTR_MAX;
242 }
243
244 if ( !DateTime_SetRange(GetHwnd(), flags, st) )
245 {
246 wxLogDebug(_T("DateTime_SetRange() failed"));
247 }
248 }
249
250 bool wxDatePickerCtrl::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
251 {
252 SYSTEMTIME st[2];
253
254 DWORD flags = DateTime_GetRange(GetHwnd(), st);
255 if ( dt1 )
256 {
257 if ( flags & GDTR_MIN )
258 wxFromSystemTime(dt1, st[0]);
259 else
260 *dt1 = wxDefaultDateTime;
261 }
262
263 if ( dt2 )
264 {
265 if ( flags & GDTR_MAX )
266 wxFromSystemTime(dt2, st[1]);
267 else
268 *dt2 = wxDefaultDateTime;
269 }
270
271 return flags != 0;
272 }
273
274 // ----------------------------------------------------------------------------
275 // wxDatePickerCtrl events
276 // ----------------------------------------------------------------------------
277
278 bool
279 wxDatePickerCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
280 {
281 NMHDR* hdr = (NMHDR *)lParam;
282 switch ( hdr->code )
283 {
284 case DTN_DATETIMECHANGE:
285 NMDATETIMECHANGE *dtch = (NMDATETIMECHANGE *)hdr;
286 wxDateTime dt;
287 if ( dtch->dwFlags == GDT_VALID )
288 wxFromSystemTime(&dt, dtch->st);
289
290 wxDateEvent event(this, dt, wxEVT_DATE_CHANGED);
291 if ( GetEventHandler()->ProcessEvent(event) )
292 {
293 *result = 0;
294 return true;
295 }
296 }
297
298 return wxDatePickerCtrlBase::MSWOnNotify(idCtrl, lParam, result);
299 }
300
301 #endif // wxUSE_DATEPICKCTRL
302