]> git.saurik.com Git - wxWidgets.git/blob - src/generic/datectlg.cpp
Add support for wxSL_INVERSE flag. Also uses new inverse logic to make Mac vertical...
[wxWidgets.git] / src / generic / datectlg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: generic/datectlg.cpp
3 // Purpose: generic wxDatePickerCtrlGeneric implementation
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
26 #if wxUSE_DATEPICKCTRL
27
28 #include "wx/datectrl.h"
29
30 // use this version if we're explicitly requested to do it or if it's the only
31 // one we have
32 #if wxUSE_DATEPICKCTRL_GENERIC || !defined(wxHAS_NATIVE_DATEPICKCTRL)
33
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
43 // otherwise it's defined in the native version implementation
44 #ifndef wxHAS_NATIVE_DATEPICKCTRL
45 #define _WX_DEFINE_DATE_EVENTS_
46 #endif
47
48 #include "wx/dateevt.h"
49 #include "wx/generic/datectrl.h"
50
51 #include "wx/calctrl.h"
52 #include "wx/popupwin.h"
53 #include "wx/renderer.h"
54
55 // ----------------------------------------------------------------------------
56 // constants
57 // ----------------------------------------------------------------------------
58
59 enum
60 {
61 CTRLID_TXT = 101,
62 CTRLID_CAL,
63 CTRLID_BTN,
64 CTRLID_PAN
65 };
66
67 #ifndef DEFAULT_ITEM_WIDTH
68 #define DEFAULT_ITEM_WIDTH 100
69 #endif
70
71 // ============================================================================
72 // wxDatePickerCtrlGeneric implementation
73 // ============================================================================
74
75 BEGIN_EVENT_TABLE(wxDatePickerCtrlGeneric, wxDatePickerCtrlBase)
76 EVT_BUTTON(CTRLID_BTN, wxDatePickerCtrlGeneric::OnClick)
77 EVT_TEXT(CTRLID_TXT, wxDatePickerCtrlGeneric::OnText)
78 EVT_CHILD_FOCUS(wxDatePickerCtrlGeneric::OnChildSetFocus)
79 END_EVENT_TABLE()
80
81 #ifndef wxHAS_NATIVE_DATEPICKCTRL
82 IMPLEMENT_DYNAMIC_CLASS(wxDatePickerCtrl, wxDatePickerCtrlBase)
83 #endif
84
85 // ----------------------------------------------------------------------------
86 // creation
87 // ----------------------------------------------------------------------------
88
89 bool 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)
96 {
97 wxASSERT_MSG( !(style & wxDP_SPIN),
98 _T("wxDP_SPIN style not supported, use wxDP_DEFAULT") );
99
100 if ( !wxControl::Create(parent, id, pos, size,
101 style | wxCLIP_CHILDREN | wxWANTS_CHARS,
102 wxDefaultValidator, name) )
103
104 {
105 return false;
106 }
107
108 InheritAttributes();
109
110 m_txt = new wxTextCtrl(this, CTRLID_TXT);
111 m_txt->Connect(wxID_ANY, wxID_ANY, wxEVT_KEY_DOWN,
112 (wxObjectEventFunction)
113 (wxEventFunction)
114 (wxCharEventFunction)
115 &wxDatePickerCtrlGeneric::OnEditKey,
116 0, this);
117 m_txt->Connect(wxID_ANY, wxID_ANY, wxEVT_KILL_FOCUS,
118 (wxObjectEventFunction)
119 (wxEventFunction)
120 (wxFocusEventFunction)
121 &wxDatePickerCtrlGeneric::OnKillFocus,
122 0, this);
123
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;
140
141 m_popup = new wxPopupWindow(this);
142 m_popup->SetFont(GetFont());
143
144 wxPanel *panel=new wxPanel(m_popup, CTRLID_PAN,
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,
151 (wxObjectEventFunction)
152 (wxEventFunction)
153 (wxCalendarEventFunction)
154 &wxDatePickerCtrlGeneric::OnSelChange,
155 0, this);
156 m_cal->Connect(wxID_ANY, wxID_ANY, wxEVT_KEY_DOWN,
157 (wxObjectEventFunction)
158 (wxEventFunction)
159 (wxCharEventFunction)
160 &wxDatePickerCtrlGeneric::OnCalKey,
161 0, this);
162 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_DOUBLECLICKED,
163 (wxObjectEventFunction)
164 (wxEventFunction)
165 (wxCalendarEventFunction)
166 &wxDatePickerCtrlGeneric::OnSelChange,
167 0, this);
168 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_DAY_CHANGED,
169 (wxObjectEventFunction)
170 (wxEventFunction)
171 (wxCalendarEventFunction)
172 &wxDatePickerCtrlGeneric::OnSelChange,
173 0, this);
174 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_MONTH_CHANGED,
175 (wxObjectEventFunction)
176 (wxEventFunction)
177 (wxCalendarEventFunction)
178 &wxDatePickerCtrlGeneric::OnSelChange,
179 0, this);
180 m_cal->Connect(CTRLID_CAL, CTRLID_CAL, wxEVT_CALENDAR_YEAR_CHANGED,
181 (wxObjectEventFunction)
182 (wxEventFunction)
183 (wxCalendarEventFunction)
184 &wxDatePickerCtrlGeneric::OnSelChange,
185 0, this);
186
187 wxWindow *yearControl = m_cal->GetYearControl();
188
189 Connect(wxID_ANY, wxID_ANY, wxEVT_SET_FOCUS,
190 (wxObjectEventFunction)
191 (wxEventFunction)
192 (wxFocusEventFunction)
193 &wxDatePickerCtrlGeneric::OnSetFocus);
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
207 SetFormat(wxT("%x"));
208
209 if (date.IsValid())
210 m_txt->SetValue(date.Format(m_format));
211
212
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);
230 yearControl->SetSize(width-yearSize.x-CALBORDER/2, yearPosition.y,
231 yearSize.x, yearSize.y);
232 m_cal->GetMonthControl()->Move(0, 0);
233
234
235
236 panel->SetClientSize(width+CALBORDER/2, calSize.y-2+CALBORDER);
237 m_popup->SetClientSize(panel->GetSize());
238 m_popup->Hide();
239
240 return true;
241 }
242
243
244 void wxDatePickerCtrlGeneric::Init()
245 {
246 m_popup = NULL;
247 m_txt = NULL;
248 m_cal = NULL;
249 m_btn = NULL;
250
251 m_dropped = false;
252 m_ignoreDrop = false;
253 }
254
255
256 bool wxDatePickerCtrlGeneric::Destroy()
257 {
258 if (m_cal)
259 m_cal->Destroy();
260 if (m_popup)
261 m_popup->Destroy();
262 if (m_txt)
263 m_txt->Destroy();
264 if (m_btn)
265 m_btn->Destroy();
266
267 m_popup = NULL;
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
279 void wxDatePickerCtrlGeneric::DoMoveWindow(int x, int y, int w, int h)
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
292 wxSize wxDatePickerCtrlGeneric::DoGetBestSize() const
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
300 bool wxDatePickerCtrlGeneric::Show(bool show)
301 {
302 if ( !wxControl::Show(show) )
303 {
304 return false;
305 }
306
307 if (!show)
308 {
309 if (m_popup)
310 {
311 m_popup->Hide();
312 m_dropped = false;
313 }
314 }
315
316 return true;
317 }
318
319
320 bool wxDatePickerCtrlGeneric::Enable(bool enable)
321 {
322 if ( !wxControl::Enable(enable) )
323 {
324 return false;
325 }
326
327 if (!enable)
328 {
329 if (m_cal)
330 m_cal->Hide();
331 }
332 if (m_btn)
333 m_btn->Enable(enable);
334 return true;
335 }
336
337 // ----------------------------------------------------------------------------
338 // wxDatePickerCtrlGeneric API
339 // ----------------------------------------------------------------------------
340
341 bool
342 wxDatePickerCtrlGeneric::SetDateRange(const wxDateTime& lowerdate,
343 const wxDateTime& upperdate)
344 {
345 return m_cal->SetDateRange(lowerdate, upperdate);
346 }
347
348 bool wxDatePickerCtrlGeneric::SetFormat(const wxChar *fmt)
349 {
350 wxString currentText;
351 wxDateTime currentDate;
352 if (m_txt)
353 {
354 currentText = m_txt->GetValue();
355 if (!currentText.empty())
356 currentDate.ParseFormat(currentText, m_format);
357 }
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 }
383 else if (n == (dt.GetYear() % 100))
384 {
385 m_format.Append(wxT("%y"));
386 p += 2;
387 }
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);
410
411 if (!currentText.empty())
412 m_txt->SetValue(currentDate.Format(m_format));
413 }
414 return true;
415 }
416
417
418 wxDateTime wxDatePickerCtrlGeneric::GetValue() const
419 {
420 wxDateTime dt;
421 wxString txt=m_txt->GetValue();
422
423 if (!txt.empty())
424 dt.ParseFormat(txt, m_format);
425
426 return dt;
427 }
428
429
430 void wxDatePickerCtrlGeneric::SetValue(const wxDateTime& date)
431 {
432 if (m_cal)
433 {
434 if (date.IsValid())
435 m_txt->SetValue(date.Format(m_format));
436 else
437 m_txt->SetValue(wxEmptyString);
438 }
439 }
440
441
442 bool wxDatePickerCtrlGeneric::GetRange(wxDateTime *dt1, wxDateTime *dt2) const
443 {
444 if (dt1)
445 *dt1 = m_cal->GetLowerDateLimit();
446 if (dt1)
447 *dt2 = m_cal->GetUpperDateLimit();
448 return true;
449 }
450
451
452 void
453 wxDatePickerCtrlGeneric::SetRange(const wxDateTime &dt1, const wxDateTime &dt2)
454 {
455 m_cal->SetDateRange(dt1, dt2);
456 }
457
458 // ----------------------------------------------------------------------------
459 // event handlers
460 // ----------------------------------------------------------------------------
461
462 void wxDatePickerCtrlGeneric::DropDown(bool down)
463 {
464 if (m_popup)
465 {
466 if (down)
467 {
468 wxDateTime dt;
469 if (!m_txt->GetValue().empty())
470 dt.ParseFormat(m_txt->GetValue(), m_format);
471
472 if (dt.IsValid())
473 m_cal->SetDate(dt);
474 else
475 m_cal->SetDate(wxDateTime::Today());
476
477 wxPoint pos=GetParent()->ClientToScreen(GetPosition());
478 m_popup->Move(pos.x, pos.y + GetSize().y);
479 m_popup->Show();
480 m_dropped = true;
481 }
482 else
483 {
484 if (m_dropped)
485 m_popup->Hide();
486 m_dropped = false;
487 }
488 }
489 }
490
491
492 void wxDatePickerCtrlGeneric::OnChildSetFocus(wxChildFocusEvent &ev)
493 {
494 ev.Skip();
495 m_ignoreDrop = false;
496
497 wxWindow *w=(wxWindow*)ev.GetEventObject();
498 while (w)
499 {
500 if (w == m_popup)
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
514 void wxDatePickerCtrlGeneric::OnClick(wxCommandEvent& WXUNUSED(event))
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
529 void wxDatePickerCtrlGeneric::OnSetFocus(wxFocusEvent& WXUNUSED(ev))
530 {
531 if (m_txt)
532 {
533 m_txt->SetFocus();
534 m_txt->SetSelection(0, 100);
535 }
536 }
537
538
539 void wxDatePickerCtrlGeneric::OnKillFocus(wxFocusEvent &ev)
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
552 void wxDatePickerCtrlGeneric::OnSelChange(wxCalendarEvent &ev)
553 {
554 if (m_cal)
555 {
556 m_txt->SetValue(m_cal->GetDate().Format(m_format));
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
569 void wxDatePickerCtrlGeneric::OnText(wxCommandEvent &ev)
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;
579 if (!txt.empty())
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
595 void wxDatePickerCtrlGeneric::OnEditKey(wxKeyEvent & ev)
596 {
597 if (ev.GetKeyCode() == WXK_DOWN && !ev.HasModifiers())
598 DropDown();
599 else
600 ev.Skip();
601 }
602
603
604 void wxDatePickerCtrlGeneric::OnCalKey(wxKeyEvent & ev)
605 {
606 if (ev.GetKeyCode() == WXK_ESCAPE && !ev.HasModifiers())
607 DropDown(false);
608 else
609 ev.Skip();
610 }
611
612 #endif // wxUSE_DATEPICKCTRL_GENERIC
613
614 #endif // wxUSE_DATEPICKCTRL
615