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