]> git.saurik.com Git - wxWidgets.git/blame - src/univ/combobox.cpp
show the selected item with customs colour correctly when the control doesn't have...
[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
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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:
61fef19b 96 void OnButton(wxCommandEvent& WXUNUSED(event)) { m_combo->ShowPopup(); }
1e6feb95 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);
8a39593e
JS
126 virtual void SetSelection(int n, bool select)
127 { wxListBox::SetSelection( n, select); };
1e6feb95
VZ
128 virtual wxControl *GetControl() { return this; }
129 virtual void OnShow();
c18670e4 130 virtual wxCoord GetBestWidth() const;
1e6feb95
VZ
131
132protected:
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
55f095d4
VZ
139 // set m_clicked value from here
140 void OnLeftUp(wxMouseEvent& event);
141
1e6feb95
VZ
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
150private:
55f095d4
VZ
151 // has the mouse been released on this control?
152 bool m_clicked;
153
1e6feb95
VZ
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
162class wxComboTextCtrl : public wxTextCtrl
163{
164public:
165 wxComboTextCtrl(wxComboControl *combo,
166 const wxString& value,
167 long style,
168 const wxValidator& validator);
169
170protected:
171 void OnKey(wxKeyEvent& event);
172 void OnText(wxCommandEvent& event);
173
174private:
175 wxComboControl *m_combo;
176
177 DECLARE_EVENT_TABLE()
178};
179
180// ----------------------------------------------------------------------------
181// event tables and such
182// ----------------------------------------------------------------------------
183
184BEGIN_EVENT_TABLE(wxComboButton, wxButton)
185 EVT_BUTTON(-1, wxComboButton::OnButton)
186END_EVENT_TABLE()
187
188BEGIN_EVENT_TABLE(wxComboListBox, wxListBox)
189 EVT_LISTBOX(-1, wxComboListBox::OnSelect)
190 EVT_LISTBOX_DCLICK(-1, wxComboListBox::OnSelect)
191 EVT_MOTION(wxComboListBox::OnMouseMove)
55f095d4 192 EVT_LEFT_UP(wxComboListBox::OnLeftUp)
1e6feb95
VZ
193END_EVENT_TABLE()
194
195BEGIN_EVENT_TABLE(wxComboControl, wxControl)
196 EVT_KEY_DOWN(wxComboControl::OnKey)
197 EVT_KEY_UP(wxComboControl::OnKey)
198END_EVENT_TABLE()
199
200BEGIN_EVENT_TABLE(wxComboTextCtrl, wxTextCtrl)
201 EVT_KEY_DOWN(wxComboTextCtrl::OnKey)
202 EVT_KEY_UP(wxComboTextCtrl::OnKey)
203 EVT_TEXT(-1, wxComboTextCtrl::OnText)
204END_EVENT_TABLE()
205
4e352a3f 206IMPLEMENT_DYNAMIC_CLASS(wxComboBox, wxControl)
1e6feb95
VZ
207
208// ============================================================================
209// implementation
210// ============================================================================
211
212// ----------------------------------------------------------------------------
213// wxComboControl creation
214// ----------------------------------------------------------------------------
215
216void wxComboControl::Init()
217{
218 m_popup = (wxComboPopup *)NULL;
219 m_winPopup = (wxPopupComboWindow *)NULL;
220 m_isPopupShown = FALSE;
9f41d601
RR
221 m_btn = NULL;
222 m_text = NULL;
1e6feb95
VZ
223}
224
225bool 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
e4606ed9
VZ
261 SetBestSize(size);
262 Move(pos);
1e6feb95
VZ
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
279wxComboControl::~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
294void wxComboControl::DoSetSize(int x, int y,
61fef19b 295 int width, int WXUNUSED(height),
1e6feb95
VZ
296 int sizeFlags)
297{
298 // combo height is always fixed
299 wxControl::DoSetSize(x, y, width, DoGetBestSize().y, sizeFlags);
300}
301
302wxSize wxComboControl::DoGetBestClientSize() const
303{
304 wxSize sizeBtn = m_btn->GetBestSize(),
305 sizeText = m_text->GetBestSize();
e2ca829e 306 wxCoord widthPopup = 0;
1e6feb95 307
e2ca829e
JS
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));
1e6feb95
VZ
315}
316
317void 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
e4606ed9 328 wxSize sizeBtn = m_btn->GetBestSize();
1e6feb95
VZ
329
330 wxCoord wText = width - sizeBtn.x;
c2ef70ec
VS
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);
1e6feb95
VZ
334}
335
336// ----------------------------------------------------------------------------
337// operations
338// ----------------------------------------------------------------------------
339
340bool 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
351bool wxComboControl::Show(bool show)
352{
353 if ( !wxControl::Show(show) )
354 return FALSE;
355
9f41d601
RR
356 if (m_btn)
357 m_btn->Show(show);
55f095d4 358
9f41d601
RR
359 if (m_text)
360 m_text->Show(show);
1e6feb95
VZ
361
362 return TRUE;
363}
364
d4e5272b
JS
365#if wxUSE_TOOLTIPS
366void 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
1e6feb95
VZ
388// ----------------------------------------------------------------------------
389// popup window handling
390// ----------------------------------------------------------------------------
391
392void wxComboControl::SetPopupControl(wxComboPopup *popup)
393{
394 m_popup = popup;
395}
396
397void 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
55f095d4 422 m_popup->OnShow();
1e6feb95
VZ
423 m_winPopup->Popup(m_text);
424 m_text->SelectAll();
425 m_popup->SetSelection(m_text->GetValue());
426
427 m_isPopupShown = TRUE;
428}
429
430void 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
440void wxComboControl::OnSelect(const wxString& value)
441{
442 m_text->SetValue(value);
443 m_text->SelectAll();
444
445 OnDismiss();
446}
447
448void wxComboControl::OnDismiss()
449{
450 HidePopup();
451 m_text->SetFocus();
452}
453
454// ----------------------------------------------------------------------------
455// wxComboTextCtrl
456// ----------------------------------------------------------------------------
457
458wxComboTextCtrl::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
470void 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
496void 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
524wxComboListBox::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
535wxComboListBox::~wxComboListBox()
536{
537}
538
539bool 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
560void wxComboListBox::OnSelect(wxCommandEvent& event)
561{
55f095d4
VZ
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
1e6feb95
VZ
578}
579
580void wxComboListBox::OnShow()
581{
55f095d4
VZ
582 // nobody clicked us yet
583 m_clicked = FALSE;
1e6feb95
VZ
584}
585
586bool 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
55f095d4
VZ
602void wxComboListBox::OnLeftUp(wxMouseEvent& event)
603{
604 // we should dismiss the combo now
605 m_clicked = TRUE;
606
607 event.Skip();
608}
609
1e6feb95
VZ
610void 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
e2ca829e
JS
628wxCoord wxComboListBox::GetBestWidth() const
629{
630 wxSize size = wxListBox::GetBestSize();
631 return size.x;
632}
633
1e6feb95
VZ
634wxSize 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
655void wxComboBox::Init()
656{
657 m_lbox = (wxListBox *)NULL;
658}
659
660bool 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
687wxComboBox::~wxComboBox()
688{
689}
690
691// ----------------------------------------------------------------------------
692// wxComboBox methods forwarded to wxTextCtrl
693// ----------------------------------------------------------------------------
694
695wxString wxComboBox::GetValue() const
696{
697 return GetText()->GetValue();
698}
699
700void wxComboBox::SetValue(const wxString& value)
701{
702 GetText()->SetValue(value);
703}
704
705void wxComboBox::Copy()
706{
707 GetText()->Copy();
708}
709
710void wxComboBox::Cut()
711{
712 GetText()->Cut();
713}
714
715void wxComboBox::Paste()
716{
717 GetText()->Paste();
718}
719
720void wxComboBox::SetInsertionPoint(long pos)
721{
722 GetText()->SetInsertionPoint(pos);
723}
724
725void wxComboBox::SetInsertionPointEnd()
726{
727 GetText()->SetInsertionPointEnd();
728}
729
730long wxComboBox::GetInsertionPoint() const
731{
732 return GetText()->GetInsertionPoint();
733}
734
735long wxComboBox::GetLastPosition() const
736{
737 return GetText()->GetLastPosition();
738}
739
740void wxComboBox::Replace(long from, long to, const wxString& value)
741{
742 GetText()->Replace(from, to, value);
743}
744
745void wxComboBox::Remove(long from, long to)
746{
747 GetText()->Remove(from, to);
748}
749
750void wxComboBox::SetSelection(long from, long to)
751{
752 GetText()->SetSelection(from, to);
753}
754
755void wxComboBox::SetEditable(bool editable)
756{
757 GetText()->SetEditable(editable);
758}
759
760// ----------------------------------------------------------------------------
761// wxComboBox methods forwarded to wxListBox
762// ----------------------------------------------------------------------------
763
764void wxComboBox::Clear()
765{
766 GetLBox()->Clear();
48aa18c0 767 GetText()->SetValue(wxEmptyString);
1e6feb95
VZ
768}
769
770void wxComboBox::Delete(int n)
771{
48aa18c0
JS
772 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Delete") );
773
774 if (GetSelection() == n)
775 GetText()->SetValue(wxEmptyString);
776
1e6feb95
VZ
777 GetLBox()->Delete(n);
778}
779
780int wxComboBox::GetCount() const
781{
782 return GetLBox()->GetCount();
783}
784
785wxString wxComboBox::GetString(int n) const
786{
48aa18c0
JS
787 wxCHECK_MSG( (n >= 0) && (n < GetCount()), wxEmptyString, _T("invalid index in wxComboBox::GetString") );
788
1e6feb95
VZ
789 return GetLBox()->GetString(n);
790}
791
792void wxComboBox::SetString(int n, const wxString& s)
793{
48aa18c0
JS
794 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::SetString") );
795
1e6feb95
VZ
796 GetLBox()->SetString(n, s);
797}
798
799int wxComboBox::FindString(const wxString& s) const
800{
801 return GetLBox()->FindString(s);
802}
803
804void wxComboBox::Select(int n)
805{
48aa18c0 806 wxCHECK_RET( (n >= 0) && (n < GetCount()), _T("invalid index in wxComboBox::Select") );
1e6feb95
VZ
807
808 GetLBox()->SetSelection(n);
809 GetText()->SetValue(GetLBox()->GetString(n));
810}
811
812int wxComboBox::GetSelection() const
813{
48aa18c0 814#if 1 // FIXME:: What is the correct behavior?
1e6feb95 815 // if the current value isn't one of the listbox strings, return -1
48aa18c0
JS
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!
1e6feb95 821 return FindString(GetText()->GetValue());
48aa18c0 822#endif
1e6feb95
VZ
823}
824
825int wxComboBox::DoAppend(const wxString& item)
826{
827 return GetLBox()->Append(item);
828}
829
243dbf1a
VZ
830int 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
3f85391e 838 GetLBox()->Insert(item, pos);
243dbf1a
VZ
839 return pos;
840}
841
1e6feb95
VZ
842void wxComboBox::DoSetItemClientData(int n, void* clientData)
843{
844 GetLBox()->SetClientData(n, clientData);
845}
846
847void *wxComboBox::DoGetItemClientData(int n) const
848{
849 return GetLBox()->GetClientData(n);
850}
851
852void wxComboBox::DoSetItemClientObject(int n, wxClientData* clientData)
853{
854 GetLBox()->SetClientObject(n, clientData);
855}
856
857wxClientData* wxComboBox::DoGetItemClientObject(int n) const
858{
859 return GetLBox()->GetClientObject(n);
860}
861
862// ----------------------------------------------------------------------------
863// input handling
864// ----------------------------------------------------------------------------
865
2e9f62da 866void wxComboControl::OnKey(wxKeyEvent& event)
1e6feb95
VZ
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
879bool 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
916wxStdComboBoxInputHandler::wxStdComboBoxInputHandler(wxInputHandler *inphand)
917 : wxStdInputHandler(inphand)
918{
919}
920
23645bfa 921bool wxStdComboBoxInputHandler::HandleKey(wxInputConsumer *consumer,
1e6feb95
VZ
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 {
23645bfa 941 consumer->PerformAction(action);
1e6feb95
VZ
942
943 return TRUE;
944 }
945 }
946
23645bfa 947 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1e6feb95
VZ
948}
949
950#endif // wxUSE_COMBOBOX