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