]> git.saurik.com Git - wxWidgets.git/blame - src/generic/datectlg.cpp
Life! made more WinCE-friendly
[wxWidgets.git] / src / generic / datectlg.cpp
CommitLineData
39df3acd 1/////////////////////////////////////////////////////////////////////////////
d5ae99f5 2// Name: generic/datectlg.cpp
7ae712f5 3// Purpose: generic wxDatePickerCtrlGeneric implementation
39df3acd
VZ
4// Author: Andreas Pflug
5// Modified by:
6// Created: 2005-01-19
7// RCS-ID: $Id$
8// Copyright: (c) 2005 Andreas Pflug <pgadmin@pse-consulting.de>
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
7ae712f5
VZ
26#if wxUSE_DATEPICKCTRL
27
15c86b39 28#include "wx/datectrl.h"
7ae712f5
VZ
29
30// use this version if we're explicitly requested to do it or if it's the only
31// one we have
15c86b39 32#if wxUSE_DATEPICKCTRL_GENERIC || !defined(wxHAS_NATIVE_DATEPICKCTRL)
7ae712f5 33
a962d4e0
KH
34#ifndef WX_PRECOMP
35 #include "wx/bmpbuttn.h"
36 #include "wx/dialog.h"
37 #include "wx/dcmemory.h"
38 #include "wx/panel.h"
39 #include "wx/textctrl.h"
40 #include "wx/valtext.h"
41#endif
42
7ae712f5 43// otherwise it's defined in the native version implementation
15c86b39 44#ifndef wxHAS_NATIVE_DATEPICKCTRL
7ae712f5
VZ
45 #define _WX_DEFINE_DATE_EVENTS_
46#endif
47
91edf16c 48#include "wx/dateevt.h"
b6292ff0 49#include "wx/generic/datectrl.h"
91edf16c 50
4b134bb2 51#include "wx/calctrl.h"
209afcf7 52#include "wx/popupwin.h"
4221a0e5 53#include "wx/renderer.h"
39df3acd
VZ
54
55// ----------------------------------------------------------------------------
56// constants
57// ----------------------------------------------------------------------------
58
59enum
60{
61 CTRLID_TXT = 101,
4b134bb2
VZ
62 CTRLID_CAL,
63 CTRLID_BTN,
39df3acd
VZ
64 CTRLID_PAN
65};
66
67#ifndef DEFAULT_ITEM_WIDTH
68 #define DEFAULT_ITEM_WIDTH 100
69#endif
70
71// ============================================================================
7ae712f5 72// wxDatePickerCtrlGeneric implementation
39df3acd
VZ
73// ============================================================================
74
7ae712f5
VZ
75BEGIN_EVENT_TABLE(wxDatePickerCtrlGeneric, wxDatePickerCtrlBase)
76 EVT_BUTTON(CTRLID_BTN, wxDatePickerCtrlGeneric::OnClick)
77 EVT_TEXT(CTRLID_TXT, wxDatePickerCtrlGeneric::OnText)
78 EVT_CHILD_FOCUS(wxDatePickerCtrlGeneric::OnChildSetFocus)
39df3acd
VZ
79END_EVENT_TABLE()
80
b6292ff0
VZ
81#ifndef wxHAS_NATIVE_DATEPICKCTRL
82 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxDatePickerCtrlBase)
83#endif
39df3acd
VZ
84
85// ----------------------------------------------------------------------------
86// creation
87// ----------------------------------------------------------------------------
88
7ae712f5
VZ
89bool wxDatePickerCtrlGeneric::Create(wxWindow *parent,
90 wxWindowID id,
91 const wxDateTime& date,
92 const wxPoint& pos,
93 const wxSize& size,
94 long style,
95 const wxString& name)
39df3acd 96{
29c86948
VZ
97 wxASSERT_MSG( !(style & wxDP_SPIN),
98 _T("wxDP_SPIN style not supported, use wxDP_DEFAULT") );
99
39df3acd
VZ
100 if ( !wxControl::Create(parent, id, pos, size,
101 style | wxCLIP_CHILDREN | wxWANTS_CHARS,
102 wxDefaultValidator, name) )
103
104 {
105 return false;
106 }
107
39df3acd
VZ
108 InheritAttributes();
109
4221a0e5 110 m_txt = new wxTextCtrl(this, CTRLID_TXT);
4b134bb2 111 m_txt->Connect(wxID_ANY, wxID_ANY, wxEVT_KEY_DOWN,
3a0c6181
WS
112 (wxObjectEventFunction)
113 (wxEventFunction)
114 (wxCharEventFunction)
115 &wxDatePickerCtrlGeneric::OnEditKey,
4b134bb2
VZ
116 0, this);
117 m_txt->Connect(wxID_ANY, wxID_ANY, wxEVT_KILL_FOCUS,
3a0c6181
WS
118 (wxObjectEventFunction)
119 (wxEventFunction)
120 (wxFocusEventFunction)
121 &wxDatePickerCtrlGeneric::OnKillFocus,
4b134bb2 122 0, this);
39df3acd 123
4221a0e5
VZ
124 const int height = m_txt->GetBestSize().y - 4; // FIXME: fudge
125 wxBitmap bmp(height, height);
126 {
127 wxMemoryDC dc;
128 dc.SelectObject(bmp);
129 wxRendererNative::Get().DrawComboBoxDropButton
130 (
131 this,
132 dc,
133 wxRect(0, 0, height, height)
134 );
135 }
136
137 wxBitmapButton *btn = new wxBitmapButton(this, CTRLID_BTN, bmp);
138 btn->SetMargins(0, 0);
139 m_btn = btn;
39df3acd 140
d5ae99f5
VZ
141 m_popup = new wxPopupWindow(this);
142 m_popup->SetFont(GetFont());
39df3acd 143
d5ae99f5 144 wxPanel *panel=new wxPanel(m_popup, CTRLID_PAN,
4b134bb2
VZ
145 wxPoint(0, 0), wxDefaultSize,
146 wxSUNKEN_BORDER);
147 m_cal = new wxCalendarCtrl(panel, CTRLID_CAL, wxDefaultDateTime,
148 wxPoint(0,0), wxDefaultSize,
149 wxCAL_SHOW_HOLIDAYS | wxSUNKEN_BORDER);
150 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_SEL_CHANGED,
3a0c6181
WS
151 (wxObjectEventFunction)
152 (wxEventFunction)
153 (wxCalendarEventFunction)
154 &wxDatePickerCtrlGeneric::OnSelChange,
4b134bb2
VZ
155 0, this);
156 m_cal->Connect(wxID_ANY, wxID_ANY, wxEVT_KEY_DOWN,
3a0c6181
WS
157 (wxObjectEventFunction)
158 (wxEventFunction)
159 (wxCharEventFunction)
160 &wxDatePickerCtrlGeneric::OnCalKey,
4b134bb2
VZ
161 0, this);
162 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_DOUBLECLICKED,
3a0c6181
WS
163 (wxObjectEventFunction)
164 (wxEventFunction)
165 (wxCalendarEventFunction)
166 &wxDatePickerCtrlGeneric::OnSelChange,
4b134bb2
VZ
167 0, this);
168 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_DAY_CHANGED,
3a0c6181
WS
169 (wxObjectEventFunction)
170 (wxEventFunction)
171 (wxCalendarEventFunction)
172 &wxDatePickerCtrlGeneric::OnSelChange,
4b134bb2
VZ
173 0, this);
174 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_MONTH_CHANGED,
3a0c6181
WS
175 (wxObjectEventFunction)
176 (wxEventFunction)
177 (wxCalendarEventFunction)
178 &wxDatePickerCtrlGeneric::OnSelChange,
4b134bb2
VZ
179 0, this);
180 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_YEAR_CHANGED,
3a0c6181
WS
181 (wxObjectEventFunction)
182 (wxEventFunction)
183 (wxCalendarEventFunction)
184 &wxDatePickerCtrlGeneric::OnSelChange,
4b134bb2 185 0, this);
39df3acd
VZ
186
187 wxWindow *yearControl = m_cal->GetYearControl();
188
4b134bb2 189 Connect(wxID_ANY, wxID_ANY, wxEVT_SET_FOCUS,
3a0c6181
WS
190 (wxObjectEventFunction)
191 (wxEventFunction)
192 (wxFocusEventFunction)
193 &wxDatePickerCtrlGeneric::OnSetFocus);
39df3acd
VZ
194
195 wxClientDC dc(yearControl);
196 dc.SetFont(m_font);
197 wxCoord width, dummy;
198 dc.GetTextExtent(wxT("2000"), &width, &dummy);
199 width += ConvertDialogToPixels(wxSize(20,0)).x;
200
201 wxSize calSize = m_cal->GetBestSize();
202 wxSize yearSize = yearControl->GetSize();
203 yearSize.x = width;
204
205 wxPoint yearPosition = yearControl->GetPosition();
206
d5ae99f5
VZ
207 SetFormat(wxT("%x"));
208
209 if (date.IsValid())
210 m_txt->SetValue(date.Format(m_format));
211
212
39df3acd
VZ
213#ifdef __WXMSW__
214#define CALBORDER 0
215#else
216#define CALBORDER 4
217#endif
218
219 width = yearPosition.x + yearSize.x+2+CALBORDER/2;
220 if (width < calSize.x-4)
221 width = calSize.x-4;
222
223 int calPos = (width-calSize.x)/2;
224 if (calPos == -1)
225 {
226 calPos = 0;
227 width += 2;
228 }
229 m_cal->SetSize(calPos, 0, calSize.x, calSize.y);
4b134bb2
VZ
230 yearControl->SetSize(width-yearSize.x-CALBORDER/2, yearPosition.y,
231 yearSize.x, yearSize.y);
39df3acd
VZ
232 m_cal->GetMonthControl()->Move(0, 0);
233
234
235
236 panel->SetClientSize(width+CALBORDER/2, calSize.y-2+CALBORDER);
d5ae99f5
VZ
237 m_popup->SetClientSize(panel->GetSize());
238 m_popup->Hide();
39df3acd 239
3a0c6181 240 return true;
39df3acd
VZ
241}
242
243
7ae712f5 244void wxDatePickerCtrlGeneric::Init()
39df3acd 245{
d5ae99f5 246 m_popup = NULL;
39df3acd
VZ
247 m_txt = NULL;
248 m_cal = NULL;
249 m_btn = NULL;
250
251 m_dropped = false;
252 m_ignoreDrop = false;
253}
254
255
7ae712f5 256bool wxDatePickerCtrlGeneric::Destroy()
39df3acd
VZ
257{
258 if (m_cal)
259 m_cal->Destroy();
d5ae99f5
VZ
260 if (m_popup)
261 m_popup->Destroy();
39df3acd
VZ
262 if (m_txt)
263 m_txt->Destroy();
264 if (m_btn)
265 m_btn->Destroy();
266
d5ae99f5 267 m_popup = NULL;
39df3acd
VZ
268 m_txt = NULL;
269 m_cal = NULL;
270 m_btn = NULL;
271
272 return wxControl::Destroy();
273}
274
275// ----------------------------------------------------------------------------
276// overridden base class methods
277// ----------------------------------------------------------------------------
278
7ae712f5 279void wxDatePickerCtrlGeneric::DoMoveWindow(int x, int y, int w, int h)
39df3acd
VZ
280{
281 wxControl::DoMoveWindow(x, y, w, h);
282 wxSize bs=m_btn->GetBestSize();
283 int eh=m_txt->GetBestSize().y;
284
285 m_txt->SetSize(0, 0, w-bs.x-1, h > eh ? eh : h);
286 m_btn->SetSize(w - bs.x, 0, bs.x, h > bs.y ? bs.y : h);
287
288 if (m_dropped)
289 DropDown();
290}
291
7ae712f5 292wxSize wxDatePickerCtrlGeneric::DoGetBestSize() const
39df3acd
VZ
293{
294 int bh=m_btn->GetBestSize().y;
295 int eh=m_txt->GetBestSize().y;
296 return wxSize(DEFAULT_ITEM_WIDTH, bh > eh ? bh : eh);
297}
298
299
7ae712f5 300bool wxDatePickerCtrlGeneric::Show(bool show)
39df3acd
VZ
301{
302 if ( !wxControl::Show(show) )
303 {
3a0c6181 304 return false;
39df3acd
VZ
305 }
306
307 if (!show)
308 {
d5ae99f5 309 if (m_popup)
39df3acd 310 {
d5ae99f5 311 m_popup->Hide();
39df3acd
VZ
312 m_dropped = false;
313 }
314 }
315
3a0c6181 316 return true;
39df3acd
VZ
317}
318
319
7ae712f5 320bool wxDatePickerCtrlGeneric::Enable(bool enable)
39df3acd
VZ
321{
322 if ( !wxControl::Enable(enable) )
323 {
3a0c6181 324 return false;
39df3acd
VZ
325 }
326
327 if (!enable)
328 {
329 if (m_cal)
330 m_cal->Hide();
331 }
332 if (m_btn)
333 m_btn->Enable(enable);
3a0c6181 334 return true;
39df3acd
VZ
335}
336
337// ----------------------------------------------------------------------------
7ae712f5 338// wxDatePickerCtrlGeneric API
39df3acd
VZ
339// ----------------------------------------------------------------------------
340
4b134bb2 341bool
7ae712f5
VZ
342wxDatePickerCtrlGeneric::SetDateRange(const wxDateTime& lowerdate,
343 const wxDateTime& upperdate)
4b134bb2
VZ
344{
345 return m_cal->SetDateRange(lowerdate, upperdate);
346}
347
7ae712f5 348bool wxDatePickerCtrlGeneric::SetFormat(const wxChar *fmt)
39df3acd 349{
d5ae99f5
VZ
350 wxString currentText;
351 wxDateTime currentDate;
352 if (m_txt)
353 {
354 currentText = m_txt->GetValue();
3a0c6181 355 if (!currentText.empty())
d5ae99f5
VZ
356 currentDate.ParseFormat(currentText, m_format);
357 }
39df3acd
VZ
358 wxDateTime dt;
359 dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d"));
360 wxString str=dt.Format(fmt);
361 wxChar *p=(wxChar*)str.c_str();
362
363 m_format=wxEmptyString;
364
365 while (*p)
366 {
367 int n=wxAtoi(p);
368 if (n == dt.GetDay())
369 {
370 m_format.Append(wxT("%d"));
371 p += 2;
372 }
373 else if (n == (int)dt.GetMonth()+1)
374 {
375 m_format.Append(wxT("%m"));
376 p += 2;
377 }
378 else if (n == dt.GetYear())
379 {
380 m_format.Append(wxT("%Y"));
381 p += 4;
382 }
d5ae99f5
VZ
383 else if (n == (dt.GetYear() % 100))
384 {
385 m_format.Append(wxT("%y"));
386 p += 2;
387 }
39df3acd
VZ
388 else
389 m_format.Append(*p++);
390 }
391
392 if (m_txt)
393 {
394 wxStringList valList;
395 wxChar c;
396 for (c='0'; c <= '9'; c++)
397 valList.Add(wxString(c, 1));
398 wxChar *p=(wxChar*)m_format.c_str();
399 while (*p)
400 {
401 if (*p == '%')
402 p += 2;
403 else
404 valList.Add(wxString(*p++, 1));
405 }
406 wxTextValidator tv(wxFILTER_INCLUDE_CHAR_LIST);
407 tv.SetIncludeList(valList);
408
409 m_txt->SetValidator(tv);
d5ae99f5 410
3a0c6181 411 if (!currentText.empty())
d5ae99f5 412 m_txt->SetValue(currentDate.Format(m_format));
39df3acd
VZ
413 }
414 return true;
415}
416
417
7ae712f5 418wxDateTime wxDatePickerCtrlGeneric::GetValue() const
39df3acd
VZ
419{
420 wxDateTime dt;
421 wxString txt=m_txt->GetValue();
422
3a0c6181 423 if (!txt.empty())
39df3acd
VZ
424 dt.ParseFormat(txt, m_format);
425
426 return dt;
427}
428
429
7ae712f5 430void wxDatePickerCtrlGeneric::SetValue(const wxDateTime& date)
39df3acd
VZ
431{
432 if (m_cal)
433 {
434 if (date.IsValid())
d5ae99f5 435 m_txt->SetValue(date.Format(m_format));
39df3acd
VZ
436 else
437 m_txt->SetValue(wxEmptyString);
438 }
439}
440
441
7ae712f5 442bool wxDatePickerCtrlGeneric::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
39df3acd
VZ
443{
444 if (dt1)
4b134bb2 445 *dt1 = m_cal->GetLowerDateLimit();
39df3acd 446 if (dt1)
4b134bb2 447 *dt2 = m_cal->GetUpperDateLimit();
39df3acd
VZ
448 return true;
449}
450
451
7ae712f5
VZ
452void
453wxDatePickerCtrlGeneric::SetRange(const wxDateTime &dt1, const wxDateTime &dt2)
39df3acd 454{
4b134bb2 455 m_cal->SetDateRange(dt1, dt2);
39df3acd
VZ
456}
457
458// ----------------------------------------------------------------------------
459// event handlers
460// ----------------------------------------------------------------------------
461
7ae712f5 462void wxDatePickerCtrlGeneric::DropDown(bool down)
39df3acd 463{
d5ae99f5 464 if (m_popup)
39df3acd
VZ
465 {
466 if (down)
467 {
d5ae99f5 468 wxDateTime dt;
3a0c6181 469 if (!m_txt->GetValue().empty())
39df3acd 470 dt.ParseFormat(m_txt->GetValue(), m_format);
d5ae99f5
VZ
471
472 if (dt.IsValid())
39df3acd 473 m_cal->SetDate(dt);
d5ae99f5
VZ
474 else
475 m_cal->SetDate(wxDateTime::Today());
39df3acd 476
d5ae99f5
VZ
477 wxPoint pos=GetParent()->ClientToScreen(GetPosition());
478 m_popup->Move(pos.x, pos.y + GetSize().y);
479 m_popup->Show();
39df3acd
VZ
480 m_dropped = true;
481 }
482 else
483 {
484 if (m_dropped)
d5ae99f5 485 m_popup->Hide();
39df3acd
VZ
486 m_dropped = false;
487 }
488 }
489}
490
491
7ae712f5 492void wxDatePickerCtrlGeneric::OnChildSetFocus(wxChildFocusEvent &ev)
39df3acd
VZ
493{
494 ev.Skip();
495 m_ignoreDrop = false;
496
497 wxWindow *w=(wxWindow*)ev.GetEventObject();
498 while (w)
499 {
d5ae99f5 500 if (w == m_popup)
39df3acd
VZ
501 return;
502 w = w->GetParent();
503 }
504
505 if (m_dropped)
506 {
507 DropDown(false);
508 if (ev.GetEventObject() == m_btn)
509 m_ignoreDrop = true;
510 }
511}
512
513
b6292ff0 514void wxDatePickerCtrlGeneric::OnClick(wxCommandEvent& WXUNUSED(event))
39df3acd
VZ
515{
516 if (m_ignoreDrop)
517 {
518 m_ignoreDrop = false;
519 m_txt->SetFocus();
520 }
521 else
522 {
523 DropDown();
524 m_cal->SetFocus();
525 }
526}
527
528
b6292ff0 529void wxDatePickerCtrlGeneric::OnSetFocus(wxFocusEvent& WXUNUSED(ev))
39df3acd
VZ
530{
531 if (m_txt)
532 {
533 m_txt->SetFocus();
534 m_txt->SetSelection(0, 100);
535 }
536}
537
538
7ae712f5 539void wxDatePickerCtrlGeneric::OnKillFocus(wxFocusEvent &ev)
39df3acd
VZ
540{
541 ev.Skip();
542
543 wxDateTime dt;
544 dt.ParseFormat(m_txt->GetValue(), m_format);
545 if (!dt.IsValid())
546 m_txt->SetValue(wxEmptyString);
547 else
548 m_txt->SetValue(dt.Format(m_format));
549}
550
551
7ae712f5 552void wxDatePickerCtrlGeneric::OnSelChange(wxCalendarEvent &ev)
39df3acd
VZ
553{
554 if (m_cal)
555 {
d5ae99f5 556 m_txt->SetValue(m_cal->GetDate().Format(m_format));
39df3acd
VZ
557 if (ev.GetEventType() == wxEVT_CALENDAR_DOUBLECLICKED)
558 {
559 DropDown(false);
560 m_txt->SetFocus();
561 }
562 }
563 ev.SetEventObject(this);
564 ev.SetId(GetId());
565 GetParent()->ProcessEvent(ev);
566}
567
568
7ae712f5 569void wxDatePickerCtrlGeneric::OnText(wxCommandEvent &ev)
39df3acd
VZ
570{
571 ev.SetEventObject(this);
572 ev.SetId(GetId());
573 GetParent()->ProcessEvent(ev);
574
575 // We'll create an additional event if the date is valid.
576 // If the date isn't valid, the user's probable in the middle of typing
577 wxString txt=m_txt->GetValue();
578 wxDateTime dt;
3a0c6181 579 if (!txt.empty())
39df3acd
VZ
580 {
581 dt.ParseFormat(txt, m_format);
582 if (!dt.IsValid())
583 return;
584 }
585
586 wxCalendarEvent cev(m_cal, wxEVT_CALENDAR_SEL_CHANGED);
587 cev.SetEventObject(this);
588 cev.SetId(GetId());
589 cev.SetDate(dt);
590
591 GetParent()->ProcessEvent(cev);
592}
593
594
7ae712f5 595void wxDatePickerCtrlGeneric::OnEditKey(wxKeyEvent & ev)
39df3acd
VZ
596{
597 if (ev.GetKeyCode() == WXK_DOWN && !ev.HasModifiers())
598 DropDown();
599 else
600 ev.Skip();
601}
602
603
7ae712f5 604void wxDatePickerCtrlGeneric::OnCalKey(wxKeyEvent & ev)
39df3acd
VZ
605{
606 if (ev.GetKeyCode() == WXK_ESCAPE && !ev.HasModifiers())
607 DropDown(false);
608 else
609 ev.Skip();
610}
611
7ae712f5
VZ
612#endif // wxUSE_DATEPICKCTRL_GENERIC
613
614#endif // wxUSE_DATEPICKCTRL
615