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