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