]> git.saurik.com Git - wxWidgets.git/blob - src/univ/combobox.cpp
Applied patch [ 650078 ] Add better checking to wxComboBox
[wxWidgets.git] / src / univ / combobox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: univ/combobox.cpp
3 // Purpose: wxComboControl and wxComboBox implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 15.12.00
7 // RCS-ID: $Id$
8 // Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "univcombobox.h"
22 #endif
23
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #if wxUSE_COMBOBOX
31
32 #ifndef WX_PRECOMP
33 #include "wx/log.h"
34
35 #include "wx/button.h"
36 #include "wx/combobox.h"
37 #include "wx/listbox.h"
38 #include "wx/textctrl.h"
39 #include "wx/bmpbuttn.h"
40
41 #include "wx/validate.h"
42 #endif
43
44 #include "wx/popupwin.h"
45
46 #include "wx/univ/renderer.h"
47 #include "wx/univ/inphand.h"
48 #include "wx/univ/theme.h"
49
50 /*
51 The keyboard event flow:
52
53 1. they always come to the text ctrl
54 2. it forwards the ones it doesn't process to the wxComboControl
55 3. which passes them to the popup window if it is popped up
56 */
57
58 // constants
59 // ----------------------------------------------------------------------------
60
61 // the margin between the text control and the combo button
62 static const wxCoord g_comboMargin = 2;
63
64 // ----------------------------------------------------------------------------
65 // wxComboButton is just a normal button except that it sends commands to the
66 // combobox and not its parent
67 // ----------------------------------------------------------------------------
68
69 class wxComboButton : public wxBitmapButton
70 {
71 public:
72 wxComboButton(wxComboControl *combo)
73 : wxBitmapButton(combo->GetParent(), -1, wxNullBitmap,
74 wxDefaultPosition, wxDefaultSize,
75 wxBORDER_NONE | wxBU_EXACTFIT)
76 {
77 m_combo = combo;
78
79 wxBitmap bmpNormal, bmpFocus, bmpPressed, bmpDisabled;
80
81 GetRenderer()->GetComboBitmaps(&bmpNormal,
82 &bmpFocus,
83 &bmpPressed,
84 &bmpDisabled);
85
86 SetBitmapLabel(bmpNormal);
87 SetBitmapFocus(bmpFocus.Ok() ? bmpFocus : bmpNormal);
88 SetBitmapSelected(bmpPressed.Ok() ? bmpPressed : bmpNormal);
89 SetBitmapDisabled(bmpDisabled.Ok() ? bmpDisabled : bmpNormal);
90
91 SetBestSize(wxDefaultSize);
92 }
93
94 protected:
95 void OnButton(wxCommandEvent& event) { m_combo->ShowPopup(); }
96
97 virtual wxSize DoGetBestClientSize() const
98 {
99 const wxBitmap& bmp = GetBitmapLabel();
100
101 return wxSize(bmp.GetWidth(), bmp.GetHeight());
102
103 }
104
105 private:
106 wxComboControl *m_combo;
107
108 DECLARE_EVENT_TABLE()
109 };
110
111 // ----------------------------------------------------------------------------
112 // wxComboListBox is a listbox modified to be used as a popup window in a
113 // combobox
114 // ----------------------------------------------------------------------------
115
116 class wxComboListBox : public wxListBox, public wxComboPopup
117 {
118 public:
119 // ctor and dtor
120 wxComboListBox(wxComboControl *combo, int style = 0);
121 virtual ~wxComboListBox();
122
123 // implement wxComboPopup methods
124 virtual bool SetSelection(const wxString& value);
125 virtual wxControl *GetControl() { return this; }
126 virtual void OnShow();
127
128 protected:
129 // we shouldn't return height too big from here
130 virtual wxSize DoGetBestClientSize() const;
131
132 // filter mouse move events happening outside the list box
133 void OnMouseMove(wxMouseEvent& event);
134
135 // set m_clicked value from here
136 void OnLeftUp(wxMouseEvent& event);
137
138 // called whenever the user selects or activates a listbox item
139 void OnSelect(wxCommandEvent& event);
140
141 // used to process wxUniv actions
142 bool PerformAction(const wxControlAction& action,
143 long numArg,
144 const wxString& strArg);
145
146 private:
147 // has the mouse been released on this control?
148 bool m_clicked;
149
150 DECLARE_EVENT_TABLE()
151 };
152
153 // ----------------------------------------------------------------------------
154 // wxComboTextCtrl is a simple text ctrl which forwards
155 // wxEVT_COMMAND_TEXT_UPDATED events and all key events to the combobox
156 // ----------------------------------------------------------------------------
157
158 class wxComboTextCtrl : public wxTextCtrl
159 {
160 public:
161 wxComboTextCtrl(wxComboControl *combo,
162 const wxString& value,
163 long style,
164 const wxValidator& validator);
165
166 protected:
167 void OnKey(wxKeyEvent& event);
168 void OnText(wxCommandEvent& event);
169
170 private:
171 wxComboControl *m_combo;
172
173 DECLARE_EVENT_TABLE()
174 };
175
176 // ----------------------------------------------------------------------------
177 // event tables and such
178 // ----------------------------------------------------------------------------
179
180 BEGIN_EVENT_TABLE(wxComboButton, wxButton)
181 EVT_BUTTON(-1, wxComboButton::OnButton)
182 END_EVENT_TABLE()
183
184 BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
185 EVT_LISTBOX(-1, wxComboListBox::OnSelect)
186 EVT_LISTBOX_DCLICK(-1, wxComboListBox::OnSelect)
187 EVT_MOTION(wxComboListBox::OnMouseMove)
188 EVT_LEFT_UP(wxComboListBox::OnLeftUp)
189 END_EVENT_TABLE()
190
191 BEGIN_EVENT_TABLE(wxComboControl, wxControl)
192 EVT_KEY_DOWN(wxComboControl::OnKey)
193 EVT_KEY_UP(wxComboControl::OnKey)
194 END_EVENT_TABLE()
195
196 BEGIN_EVENT_TABLE(wxComboTextCtrl, wxTextCtrl)
197 EVT_KEY_DOWN(wxComboTextCtrl::OnKey)
198 EVT_KEY_UP(wxComboTextCtrl::OnKey)
199 EVT_TEXT(-1, wxComboTextCtrl::OnText)
200 END_EVENT_TABLE()
201
202 IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
203
204 // ============================================================================
205 // implementation
206 // ============================================================================
207
208 // ----------------------------------------------------------------------------
209 // wxComboControl creation
210 // ----------------------------------------------------------------------------
211
212 void wxComboControl::Init()
213 {
214 m_popup = (wxComboPopup *)NULL;
215 m_winPopup = (wxPopupComboWindow *)NULL;
216 m_isPopupShown = FALSE;
217 m_btn = NULL;
218 m_text = NULL;
219 }
220
221 bool wxComboControl::Create(wxWindow *parent,
222 wxWindowID id,
223 const wxString& value,
224 const wxPoint& pos,
225 const wxSize& size,
226 long style,
227 const wxValidator& validator,
228 const wxString& name)
229 {
230 // first create our own window, i.e. the one which will contain all
231 // subcontrols
232 style &= ~wxBORDER_NONE;
233 style |= wxBORDER_SUNKEN;
234 if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
235 return FALSE;
236
237 // create the text control and the button as our siblings (*not* children),
238 // don't care about size/position here - they will be set in DoMoveWindow()
239 m_btn = new wxComboButton(this);
240 m_text = new wxComboTextCtrl(this,
241 value,
242 style & wxCB_READONLY ? wxTE_READONLY : 0,
243 validator);
244
245 // for compatibility with the other ports, the height specified is the
246 // combined height of the combobox itself and the popup
247 if ( size.y == -1 )
248 {
249 // ok, use default height for popup too
250 m_heightPopup = -1;
251 }
252 else
253 {
254 m_heightPopup = size.y - DoGetBestSize().y;
255 }
256
257 SetBestSize(size);
258 Move(pos);
259
260 // create the popup window immediately here to allow creating the controls
261 // with parent == GetPopupWindow() from the derived class ctor
262 m_winPopup = new wxPopupComboWindow(this);
263
264 // have to disable this window to avoid interfering it with message
265 // processing to the text and the button... but pretend it is enabled to
266 // make IsEnabled() return TRUE
267 wxControl::Enable(FALSE); // don't use non virtual Disable() here!
268 m_isEnabled = TRUE;
269
270 CreateInputHandler(wxINP_HANDLER_COMBOBOX);
271
272 return TRUE;
273 }
274
275 wxComboControl::~wxComboControl()
276 {
277 // as the button and the text control are the parent's children and not
278 // ours, we have to delete them manually - they are not deleted
279 // automatically by wxWindows when we're deleted
280 delete m_btn;
281 delete m_text;
282
283 delete m_winPopup;
284 }
285
286 // ----------------------------------------------------------------------------
287 // geometry stuff
288 // ----------------------------------------------------------------------------
289
290 void wxComboControl::DoSetSize(int x, int y,
291 int width, int height,
292 int sizeFlags)
293 {
294 // combo height is always fixed
295 wxControl::DoSetSize(x, y, width, DoGetBestSize().y, sizeFlags);
296 }
297
298 wxSize wxComboControl::DoGetBestClientSize() const
299 {
300 wxSize sizeBtn = m_btn->GetBestSize(),
301 sizeText = m_text->GetBestSize();
302
303 return wxSize(sizeText.x + g_comboMargin + sizeBtn.x, wxMax(sizeBtn.y, sizeText.y));
304 }
305
306 void wxComboControl::DoMoveWindow(int x, int y, int width, int height)
307 {
308 wxControl::DoMoveWindow(x, y, width, height);
309
310 // position the subcontrols inside the client area
311 wxRect rectBorders = GetRenderer()->GetBorderDimensions(GetBorder());
312 x += rectBorders.x;
313 y += rectBorders.y;
314 width -= rectBorders.x + rectBorders.width;
315 height -= rectBorders.y + rectBorders.height;
316
317 wxSize sizeBtn = m_btn->GetBestSize();
318
319 wxCoord wText = width - sizeBtn.x;
320 wxPoint p = GetParent() ? GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
321 m_text->SetSize(x - p.x, y - p.y, wText, height);
322 m_btn->SetSize(x - p.x + wText, y - p.y, sizeBtn.x, height);
323 }
324
325 // ----------------------------------------------------------------------------
326 // operations
327 // ----------------------------------------------------------------------------
328
329 bool wxComboControl::Enable(bool enable)
330 {
331 if ( !wxControl::Enable(enable) )
332 return FALSE;
333
334 m_btn->Enable(enable);
335 m_text->Enable(enable);
336
337 return TRUE;
338 }
339
340 bool wxComboControl::Show(bool show)
341 {
342 if ( !wxControl::Show(show) )
343 return FALSE;
344
345 if (m_btn)
346 m_btn->Show(show);
347
348 if (m_text)
349 m_text->Show(show);
350
351 return TRUE;
352 }
353
354 // ----------------------------------------------------------------------------
355 // popup window handling
356 // ----------------------------------------------------------------------------
357
358 void wxComboControl::SetPopupControl(wxComboPopup *popup)
359 {
360 m_popup = popup;
361 }
362
363 void wxComboControl::ShowPopup()
364 {
365 wxCHECK_RET( m_popup, _T("no popup to show in wxComboControl") );
366 wxCHECK_RET( !IsPopupShown(), _T("popup window already shown") );
367
368 wxControl *control = m_popup->GetControl();
369
370 // size and position the popup window correctly
371 m_winPopup->SetSize(GetSize().x,
372 m_heightPopup == -1 ? control->GetBestSize().y
373 : m_heightPopup);
374 wxSize sizePopup = m_winPopup->GetClientSize();
375 control->SetSize(0, 0, sizePopup.x, sizePopup.y);
376
377 // some controls don't accept the size we give then: e.g. a listbox may
378 // require more space to show its last row
379 wxSize sizeReal = control->GetSize();
380 if ( sizeReal != sizePopup )
381 {
382 m_winPopup->SetClientSize(sizeReal);
383 }
384
385 m_winPopup->PositionNearCombo();
386
387 // show it
388 m_popup->OnShow();
389 m_winPopup->Popup(m_text);
390 m_text->SelectAll();
391 m_popup->SetSelection(m_text->GetValue());
392
393 m_isPopupShown = TRUE;
394 }
395
396 void wxComboControl::HidePopup()
397 {
398 wxCHECK_RET( m_popup, _T("no popup to hide in wxComboControl") );
399 wxCHECK_RET( IsPopupShown(), _T("popup window not shown") );
400
401 m_winPopup->Dismiss();
402
403 m_isPopupShown = FALSE;
404 }
405
406 void wxComboControl::OnSelect(const wxString& value)
407 {
408 m_text->SetValue(value);
409 m_text->SelectAll();
410
411 OnDismiss();
412 }
413
414 void wxComboControl::OnDismiss()
415 {
416 HidePopup();
417 m_text->SetFocus();
418 }
419
420 // ----------------------------------------------------------------------------
421 // wxComboTextCtrl
422 // ----------------------------------------------------------------------------
423
424 wxComboTextCtrl::wxComboTextCtrl(wxComboControl *combo,
425 const wxString& value,
426 long style,
427 const wxValidator& validator)
428 : wxTextCtrl(combo->GetParent(), -1, value,
429 wxDefaultPosition, wxDefaultSize,
430 wxBORDER_NONE | style,
431 validator)
432 {
433 m_combo = combo;
434 }
435
436 void wxComboTextCtrl::OnText(wxCommandEvent& event)
437 {
438 if ( m_combo->IsPopupShown() )
439 {
440 m_combo->GetPopupControl()->SetSelection(GetValue());
441 }
442
443 // we need to make a copy of the event to have the correct originating
444 // object and id
445 wxCommandEvent event2 = event;
446 event2.SetEventObject(m_combo);
447 event2.SetId(m_combo->GetId());
448
449 // there is a small incompatibility with wxMSW here: the combobox gets the
450 // event before the text control in our case which corresponds to SMW
451 // CBN_EDITUPDATE notification and not CBN_EDITCHANGE one wxMSW currently
452 // uses
453 //
454 // if this is really a problem, we can play games with the event handlers
455 // to circumvent this
456 (void)m_combo->ProcessEvent(event2);
457
458 event.Skip();
459 }
460
461 // pass the keys we don't process to the combo first
462 void wxComboTextCtrl::OnKey(wxKeyEvent& event)
463 {
464 switch ( event.GetKeyCode() )
465 {
466 case WXK_RETURN:
467 // the popup control gets it first but only if it is shown
468 if ( !m_combo->IsPopupShown() )
469 break;
470 //else: fall through
471
472 case WXK_UP:
473 case WXK_DOWN:
474 case WXK_ESCAPE:
475 case WXK_PAGEDOWN:
476 case WXK_PAGEUP:
477 case WXK_PRIOR:
478 case WXK_NEXT:
479 (void)m_combo->ProcessEvent(event);
480 return;
481 }
482
483 event.Skip();
484 }
485
486 // ----------------------------------------------------------------------------
487 // wxComboListBox
488 // ----------------------------------------------------------------------------
489
490 wxComboListBox::wxComboListBox(wxComboControl *combo, int style)
491 : wxListBox(combo->GetPopupWindow(), -1,
492 wxDefaultPosition, wxDefaultSize,
493 0, NULL,
494 wxBORDER_SIMPLE | wxLB_INT_HEIGHT | style),
495 wxComboPopup(combo)
496 {
497 // we don't react to the mouse events outside the window at all
498 StopAutoScrolling();
499 }
500
501 wxComboListBox::~wxComboListBox()
502 {
503 }
504
505 bool wxComboListBox::SetSelection(const wxString& value)
506 {
507 // FindItem() would just find the current item for an empty string (it
508 // always matches), but we want to show the first one in such case
509 if ( value.empty() )
510 {
511 if ( GetCount() )
512 {
513 wxListBox::SetSelection(0);
514 }
515 //else: empty listbox - nothing to do
516 }
517 else if ( !FindItem(value) )
518 {
519 // no match att all
520 return FALSE;
521 }
522
523 return TRUE;
524 }
525
526 void wxComboListBox::OnSelect(wxCommandEvent& event)
527 {
528 if ( m_clicked )
529 {
530 // first update the combo and close the listbox
531 m_combo->OnSelect(event.GetString());
532
533 // next let the user code have the event
534
535 // all fields are already filled by the listbox, just change the event
536 // type and send it to the combo
537 wxCommandEvent event2 = event;
538 event2.SetEventType(wxEVT_COMMAND_COMBOBOX_SELECTED);
539 event2.SetEventObject(m_combo);
540 event2.SetId(m_combo->GetId());
541 m_combo->ProcessEvent(event2);
542 }
543 //else: ignore the events resultign from just moving the mouse initially
544 }
545
546 void wxComboListBox::OnShow()
547 {
548 // nobody clicked us yet
549 m_clicked = FALSE;
550 }
551
552 bool wxComboListBox::PerformAction(const wxControlAction& action,
553 long numArg,
554 const wxString& strArg)
555
556 {
557 if ( action == wxACTION_LISTBOX_FIND )
558 {
559 // we don't let the listbox handle this as instead of just using the
560 // single key presses, as usual, we use the text ctrl value as prefix
561 // and this is done by wxComboControl itself
562 return TRUE;
563 }
564
565 return wxListBox::PerformAction(action, numArg, strArg);
566 }
567
568 void wxComboListBox::OnLeftUp(wxMouseEvent& event)
569 {
570 // we should dismiss the combo now
571 m_clicked = TRUE;
572
573 event.Skip();
574 }
575
576 void wxComboListBox::OnMouseMove(wxMouseEvent& event)
577 {
578 // while a wxComboListBox is shown, it always has capture, so if it doesn't
579 // we're about to go away anyhow (normally this shouldn't happen at all,
580 // but I don't put assert here as it just might do on other platforms and
581 // it doesn't break anythign anyhow)
582 if ( this == wxWindow::GetCapture() )
583 {
584 if ( HitTest(event.GetPosition()) == wxHT_WINDOW_INSIDE )
585 {
586 event.Skip();
587 }
588 //else: popup shouldn't react to the mouse motions outside it, it only
589 // captures the mouse to be able to detect when it must be
590 // dismissed, so don't call Skip()
591 }
592 }
593
594 wxSize wxComboListBox::DoGetBestClientSize() const
595 {
596 // don't return size too big or we risk to not fit on the screen
597 wxSize size = wxListBox::DoGetBestClientSize();
598 wxCoord hChar = GetCharHeight();
599
600 int nLines = size.y / hChar;
601
602 // 10 is the same limit as used by wxMSW
603 if ( nLines > 10 )
604 {
605 size.y = 10*hChar;
606 }
607
608 return size;
609 }
610
611 // ----------------------------------------------------------------------------
612 // wxComboBox
613 // ----------------------------------------------------------------------------
614
615 void wxComboBox::Init()
616 {
617 m_lbox = (wxListBox *)NULL;
618 }
619
620 bool wxComboBox::Create(wxWindow *parent,
621 wxWindowID id,
622 const wxString& value,
623 const wxPoint& pos,
624 const wxSize& size,
625 int n,
626 const wxString *choices,
627 long style,
628 const wxValidator& validator,
629 const wxString& name)
630 {
631 if ( !wxComboControl::Create(parent, id, value, pos, size, style,
632 validator, name) )
633 {
634 return FALSE;
635 }
636
637 wxComboListBox *combolbox =
638 new wxComboListBox(this, style & wxCB_SORT ? wxLB_SORT : 0);
639 m_lbox = combolbox;
640 m_lbox->Set(n, choices);
641
642 SetPopupControl(combolbox);
643
644 return TRUE;
645 }
646
647 wxComboBox::~wxComboBox()
648 {
649 }
650
651 // ----------------------------------------------------------------------------
652 // wxComboBox methods forwarded to wxTextCtrl
653 // ----------------------------------------------------------------------------
654
655 wxString wxComboBox::GetValue() const
656 {
657 return GetText()->GetValue();
658 }
659
660 void wxComboBox::SetValue(const wxString& value)
661 {
662 GetText()->SetValue(value);
663 }
664
665 void wxComboBox::Copy()
666 {
667 GetText()->Copy();
668 }
669
670 void wxComboBox::Cut()
671 {
672 GetText()->Cut();
673 }
674
675 void wxComboBox::Paste()
676 {
677 GetText()->Paste();
678 }
679
680 void wxComboBox::SetInsertionPoint(long pos)
681 {
682 GetText()->SetInsertionPoint(pos);
683 }
684
685 void wxComboBox::SetInsertionPointEnd()
686 {
687 GetText()->SetInsertionPointEnd();
688 }
689
690 long wxComboBox::GetInsertionPoint() const
691 {
692 return GetText()->GetInsertionPoint();
693 }
694
695 long wxComboBox::GetLastPosition() const
696 {
697 return GetText()->GetLastPosition();
698 }
699
700 void wxComboBox::Replace(long from, long to, const wxString& value)
701 {
702 GetText()->Replace(from, to, value);
703 }
704
705 void wxComboBox::Remove(long from, long to)
706 {
707 GetText()->Remove(from, to);
708 }
709
710 void wxComboBox::SetSelection(long from, long to)
711 {
712 GetText()->SetSelection(from, to);
713 }
714
715 void wxComboBox::SetEditable(bool editable)
716 {
717 GetText()->SetEditable(editable);
718 }
719
720 // ----------------------------------------------------------------------------
721 // wxComboBox methods forwarded to wxListBox
722 // ----------------------------------------------------------------------------
723
724 void wxComboBox::Clear()
725 {
726 GetLBox()->Clear();
727 GetText()->SetValue(wxEmptyString);
728 }
729
730 void wxComboBox::Delete(int n)
731 {
732 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Delete") );
733
734 if (GetSelection() == n)
735 GetText()->SetValue(wxEmptyString);
736
737 GetLBox()->Delete(n);
738 }
739
740 int wxComboBox::GetCount() const
741 {
742 return GetLBox()->GetCount();
743 }
744
745 wxString wxComboBox::GetString(int n) const
746 {
747 wxCHECK_MSG( (n >= 0) && (n < GetCount()), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
748
749 return GetLBox()->GetString(n);
750 }
751
752 void wxComboBox::SetString(int n, const wxString& s)
753 {
754 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::SetString") );
755
756 GetLBox()->SetString(n, s);
757 }
758
759 int wxComboBox::FindString(const wxString& s) const
760 {
761 return GetLBox()->FindString(s);
762 }
763
764 void wxComboBox::Select(int n)
765 {
766 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Select") );
767
768 GetLBox()->SetSelection(n);
769 GetText()->SetValue(GetLBox()->GetString(n));
770 }
771
772 int wxComboBox::GetSelection() const
773 {
774 #if 1 // FIXME:: What is the correct behavior?
775 // if the current value isn't one of the listbox strings, return -1
776 return GetLBox()->GetSelection();
777 #else
778 // Why oh why is this done this way?
779 // It is not because the value displayed in the text can be found
780 // in the list that it is the item that is selected!
781 return FindString(GetText()->GetValue());
782 #endif
783 }
784
785 int wxComboBox::DoAppend(const wxString& item)
786 {
787 return GetLBox()->Append(item);
788 }
789
790 void wxComboBox::DoSetItemClientData(int n, void* clientData)
791 {
792 GetLBox()->SetClientData(n, clientData);
793 }
794
795 void *wxComboBox::DoGetItemClientData(int n) const
796 {
797 return GetLBox()->GetClientData(n);
798 }
799
800 void wxComboBox::DoSetItemClientObject(int n, wxClientData* clientData)
801 {
802 GetLBox()->SetClientObject(n, clientData);
803 }
804
805 wxClientData* wxComboBox::DoGetItemClientObject(int n) const
806 {
807 return GetLBox()->GetClientObject(n);
808 }
809
810 // ----------------------------------------------------------------------------
811 // input handling
812 // ----------------------------------------------------------------------------
813
814 void wxComboControl::OnKey(wxKeyEvent& event)
815 {
816 if ( m_isPopupShown )
817 {
818 // pass it to the popped up control
819 (void)m_popup->GetControl()->ProcessEvent(event);
820 }
821 else // no popup
822 {
823 event.Skip();
824 }
825 }
826
827 bool wxComboControl::PerformAction(const wxControlAction& action,
828 long numArg,
829 const wxString& strArg)
830 {
831 bool processed = FALSE;
832 if ( action == wxACTION_COMBOBOX_POPUP )
833 {
834 if ( !m_isPopupShown )
835 {
836 ShowPopup();
837
838 processed = TRUE;
839 }
840 }
841 else if ( action == wxACTION_COMBOBOX_DISMISS )
842 {
843 if ( m_isPopupShown )
844 {
845 HidePopup();
846
847 processed = TRUE;
848 }
849 }
850
851 if ( !processed )
852 {
853 // pass along
854 return wxControl::PerformAction(action, numArg, strArg);
855 }
856
857 return TRUE;
858 }
859
860 // ----------------------------------------------------------------------------
861 // wxStdComboBoxInputHandler
862 // ----------------------------------------------------------------------------
863
864 wxStdComboBoxInputHandler::wxStdComboBoxInputHandler(wxInputHandler *inphand)
865 : wxStdInputHandler(inphand)
866 {
867 }
868
869 bool wxStdComboBoxInputHandler::HandleKey(wxInputConsumer *consumer,
870 const wxKeyEvent& event,
871 bool pressed)
872 {
873 if ( pressed )
874 {
875 wxControlAction action;
876 switch ( event.GetKeyCode() )
877 {
878 case WXK_DOWN:
879 action = wxACTION_COMBOBOX_POPUP;
880 break;
881
882 case WXK_ESCAPE:
883 action = wxACTION_COMBOBOX_DISMISS;
884 break;
885 }
886
887 if ( !!action )
888 {
889 consumer->PerformAction(action);
890
891 return TRUE;
892 }
893 }
894
895 return wxStdInputHandler::HandleKey(consumer, event, pressed);
896 }
897
898 #endif // wxUSE_COMBOBOX