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